![]() |
Icinga-core 1.4.0
next gen monitoring
|
00001 /***************************************************************************** 00002 * 00003 * UTILS.C - Miscellaneous utility functions for Icinga 00004 * 00005 * Copyright (c) 1999-2009 Ethan Galstad (egalstad@nagios.org) 00006 * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors 00007 * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org) 00008 * 00009 * License: 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License version 2 as 00013 * published by the Free Software Foundation. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00023 * 00024 *****************************************************************************/ 00025 00026 #include "../include/config.h" 00027 #include "../include/common.h" 00028 #include "../include/objects.h" 00029 #include "../include/statusdata.h" 00030 #include "../include/comments.h" 00031 #include "../include/macros.h" 00032 #include "../include/icinga.h" 00033 #include "../include/netutils.h" 00034 #include "../include/broker.h" 00035 #include "../include/nebmods.h" 00036 #include "../include/nebmodules.h" 00037 00038 00039 #ifdef EMBEDDEDPERL 00040 #include "../include/epn_icinga.h" 00041 static PerlInterpreter *my_perl=NULL; 00042 int use_embedded_perl=TRUE; 00043 #endif 00044 00045 extern char *config_file; 00046 extern char *log_file; 00047 extern char *command_file; 00048 extern char *temp_file; 00049 extern char *temp_path; 00050 extern char *check_result_path; 00051 extern char *check_result_path; 00052 extern char *lock_file; 00053 extern char *log_archive_path; 00054 extern char *auth_file; 00055 extern char *p1_file; 00056 00057 extern char *nagios_user; 00058 extern char *nagios_group; 00059 00060 extern char *macro_x_names[MACRO_X_COUNT]; 00061 extern char *macro_user[MAX_USER_MACROS]; 00062 extern customvariablesmember *macro_custom_host_vars; 00063 extern customvariablesmember *macro_custom_service_vars; 00064 extern customvariablesmember *macro_custom_contact_vars; 00065 00066 extern host *macro_host_ptr; 00067 extern hostgroup *macro_hostgroup_ptr; 00068 extern service *macro_service_ptr; 00069 extern servicegroup *macro_servicegroup_ptr; 00070 extern contact *macro_contact_ptr; 00071 extern contactgroup *macro_contactgroup_ptr; 00072 00073 extern char *global_host_event_handler; 00074 extern char *global_service_event_handler; 00075 extern command *global_host_event_handler_ptr; 00076 extern command *global_service_event_handler_ptr; 00077 00078 extern char *ocsp_command; 00079 extern char *ochp_command; 00080 extern command *ocsp_command_ptr; 00081 extern command *ochp_command_ptr; 00082 00083 extern char *illegal_object_chars; 00084 extern char *illegal_output_chars; 00085 00086 extern int use_regexp_matches; 00087 extern int use_true_regexp_matching; 00088 00089 extern int sigshutdown; 00090 extern int sigrestart; 00091 extern char *sigs[35]; 00092 extern int caught_signal; 00093 extern int sig_id; 00094 00095 extern int daemon_mode; 00096 extern int daemon_dumps_core; 00097 00098 extern int nagios_pid; 00099 00100 extern int use_daemon_log; 00101 extern int use_syslog; 00102 extern int use_syslog_local_facility; 00103 extern int syslog_local_facility; 00104 00105 extern int log_notifications; 00106 extern int log_service_retries; 00107 extern int log_host_retries; 00108 extern int log_event_handlers; 00109 extern int log_external_commands; 00110 extern int log_external_commands_user; 00111 extern int log_passive_checks; 00112 00113 extern unsigned long logging_options; 00114 extern unsigned long syslog_options; 00115 00116 extern int service_check_timeout; 00117 extern int service_check_timeout_state; 00118 extern int host_check_timeout; 00119 extern int event_handler_timeout; 00120 extern int notification_timeout; 00121 extern int ocsp_timeout; 00122 extern int ochp_timeout; 00123 00124 extern int log_initial_states; 00125 00126 extern double sleep_time; 00127 extern int interval_length; 00128 extern int service_inter_check_delay_method; 00129 extern int host_inter_check_delay_method; 00130 extern int service_interleave_factor_method; 00131 extern int max_host_check_spread; 00132 extern int max_service_check_spread; 00133 00134 extern int command_check_interval; 00135 extern int check_reaper_interval; 00136 extern int max_check_reaper_time; 00137 extern int service_freshness_check_interval; 00138 extern int host_freshness_check_interval; 00139 extern int auto_rescheduling_interval; 00140 extern int auto_rescheduling_window; 00141 00142 extern int check_external_commands; 00143 extern int check_orphaned_services; 00144 extern int check_orphaned_hosts; 00145 extern int check_service_freshness; 00146 extern int check_host_freshness; 00147 extern int auto_reschedule_checks; 00148 00149 extern int additional_freshness_latency; 00150 00151 extern int use_aggressive_host_checking; 00152 extern unsigned long cached_host_check_horizon; 00153 extern unsigned long cached_service_check_horizon; 00154 extern int enable_predictive_host_dependency_checks; 00155 extern int enable_predictive_service_dependency_checks; 00156 00157 extern int soft_state_dependencies; 00158 00159 extern int retain_state_information; 00160 extern int retention_update_interval; 00161 extern int use_retained_program_state; 00162 extern int use_retained_scheduling_info; 00163 extern int retention_scheduling_horizon; 00164 extern unsigned long modified_host_process_attributes; 00165 extern unsigned long modified_service_process_attributes; 00166 extern unsigned long retained_host_attribute_mask; 00167 extern unsigned long retained_service_attribute_mask; 00168 extern unsigned long retained_contact_host_attribute_mask; 00169 extern unsigned long retained_contact_service_attribute_mask; 00170 extern unsigned long retained_process_host_attribute_mask; 00171 extern unsigned long retained_process_service_attribute_mask; 00172 00173 extern unsigned long next_comment_id; 00174 extern unsigned long next_downtime_id; 00175 extern unsigned long next_event_id; 00176 extern unsigned long next_notification_id; 00177 00178 extern int log_rotation_method; 00179 00180 extern time_t program_start; 00181 00182 extern time_t last_command_check; 00183 extern time_t last_command_status_update; 00184 extern time_t last_log_rotation; 00185 00186 extern int verify_config; 00187 extern int test_scheduling; 00188 00189 extern check_result check_result_info; 00190 00191 extern int max_parallel_service_checks; 00192 extern int currently_running_service_checks; 00193 00194 extern int enable_notifications; 00195 extern int execute_service_checks; 00196 extern int accept_passive_service_checks; 00197 extern int execute_host_checks; 00198 extern int accept_passive_host_checks; 00199 extern int enable_event_handlers; 00200 extern int obsess_over_services; 00201 extern int obsess_over_hosts; 00202 extern int enable_failure_prediction; 00203 extern int process_performance_data; 00204 00205 extern int translate_passive_host_checks; 00206 extern int passive_host_checks_are_soft; 00207 00208 extern int aggregate_status_updates; 00209 extern int status_update_interval; 00210 00211 extern int time_change_threshold; 00212 00213 extern unsigned long event_broker_options; 00214 00215 extern int process_performance_data; 00216 00217 extern int enable_flap_detection; 00218 00219 extern double low_service_flap_threshold; 00220 extern double high_service_flap_threshold; 00221 extern double low_host_flap_threshold; 00222 extern double high_host_flap_threshold; 00223 00224 extern int use_large_installation_tweaks; 00225 extern int enable_environment_macros; 00226 extern int free_child_process_memory; 00227 extern int child_processes_fork_twice; 00228 00229 extern int enable_embedded_perl; 00230 extern int use_embedded_perl_implicitly; 00231 00232 extern int stalking_event_handlers_for_hosts; 00233 extern int stalking_event_handlers_for_services; 00234 00235 extern int date_format; 00236 00237 extern contact *contact_list; 00238 extern contactgroup *contactgroup_list; 00239 extern host *host_list; 00240 extern hostgroup *hostgroup_list; 00241 extern service *service_list; 00242 extern servicegroup *servicegroup_list; 00243 extern timed_event *event_list_high; 00244 extern timed_event *event_list_low; 00245 extern notification *notification_list; 00246 extern command *command_list; 00247 extern timeperiod *timeperiod_list; 00248 00249 extern int command_file_fd; 00250 extern FILE *command_file_fp; 00251 extern int command_file_created; 00252 00253 #ifdef HAVE_TZNAME 00254 #ifdef CYGWIN 00255 extern char *_tzname[2] __declspec(dllimport); 00256 #else 00257 extern char *tzname[2]; 00258 #endif 00259 #endif 00260 00261 extern check_result *check_result_list; 00262 extern unsigned long max_check_result_file_age; 00263 00264 extern dbuf check_result_dbuf; 00265 00266 extern pthread_t worker_threads[TOTAL_WORKER_THREADS]; 00267 extern circular_buffer external_command_buffer; 00268 extern circular_buffer check_result_buffer; 00269 extern circular_buffer event_broker_buffer; 00270 extern int external_command_buffer_slots; 00271 00272 extern check_stats check_statistics[MAX_CHECK_STATS_TYPES]; 00273 00274 extern char *debug_file; 00275 extern int debug_level; 00276 extern int debug_verbosity; 00277 extern unsigned long max_debug_file_size; 00278 00279 /* from GNU defines errno as a macro, since it's a per-thread variable */ 00280 #ifndef errno 00281 extern int errno; 00282 #endif 00283 00284 int dummy; /* reduce compiler warnings */ 00285 00286 /******************************************************************/ 00287 /******************** SYSTEM COMMAND FUNCTIONS ********************/ 00288 /******************************************************************/ 00289 00290 00291 /* executes a system command - used for notifications, event handlers, etc. */ 00292 int my_system_r(icinga_macros *mac, char *cmd,int timeout,int *early_timeout,double *exectime,char **output,int max_output_length){ 00293 pid_t pid=0; 00294 int status=0; 00295 int result=0; 00296 char buffer[MAX_INPUT_BUFFER]=""; 00297 char *temp_buffer=NULL; 00298 int fd[2]; 00299 FILE *fp=NULL; 00300 int bytes_read=0; 00301 struct timeval start_time,end_time; 00302 dbuf output_dbuf; 00303 int dbuf_chunk=1024; 00304 int flags; 00305 #ifdef EMBEDDEDPERL 00306 char fname[512]=""; 00307 char *args[5]={"",DO_CLEAN, "", "", NULL }; 00308 SV *plugin_hndlr_cr=NULL; /* perl.h holds typedef struct */ 00309 char *perl_output=NULL; 00310 int count; 00311 int use_epn=FALSE; 00312 #ifdef aTHX 00313 dTHX; 00314 #endif 00315 dSP; 00316 #endif 00317 00318 00319 log_debug_info(DEBUGL_FUNCTIONS,0,"my_system_r()\n"); 00320 00321 /* initialize return variables */ 00322 if(output!=NULL) 00323 *output=NULL; 00324 *early_timeout=FALSE; 00325 *exectime=0.0; 00326 00327 /* if no command was passed, return with no error */ 00328 if(cmd==NULL) 00329 return STATE_OK; 00330 00331 log_debug_info(DEBUGL_COMMANDS,1,"Running command '%s'...\n",cmd); 00332 00333 #ifdef EMBEDDEDPERL 00334 00335 /* get"filename" component of command */ 00336 strncpy(fname,cmd,strcspn(cmd," ")); 00337 fname[strcspn(cmd," ")]='\x0'; 00338 00339 /* should we use the embedded Perl interpreter to run this script? */ 00340 use_epn=file_uses_embedded_perl(fname); 00341 00342 /* if yes, do some initialization */ 00343 if(use_epn==TRUE){ 00344 00345 args[0]=fname; 00346 args[2]=""; 00347 00348 if(strchr(cmd,' ')==NULL) 00349 args[3]=""; 00350 else 00351 args[3]=cmd+strlen(fname)+1; 00352 00353 /* call our perl interpreter to compile and optionally cache the compiled script. */ 00354 00355 ENTER; 00356 SAVETMPS; 00357 PUSHMARK(SP); 00358 00359 XPUSHs(sv_2mortal(newSVpv(args[0],0))); 00360 XPUSHs(sv_2mortal(newSVpv(args[1],0))); 00361 XPUSHs(sv_2mortal(newSVpv(args[2],0))); 00362 XPUSHs(sv_2mortal(newSVpv(args[3],0))); 00363 00364 PUTBACK; 00365 00366 call_pv("Embed::Persistent::eval_file", G_EVAL); 00367 00368 SPAGAIN; 00369 00370 if( SvTRUE(ERRSV) ){ 00371 /* 00372 * XXXX need pipe open to send the compilation failure message back to Icinga ? 00373 */ 00374 (void) POPs ; 00375 00376 dummy=asprintf(&temp_buffer,"%s", SvPVX(ERRSV)); 00377 00378 log_debug_info(DEBUGL_COMMANDS,0,"Embedded perl failed to compile %s, compile error %s\n",fname,temp_buffer); 00379 00380 logit(NSLOG_RUNTIME_WARNING,TRUE,"%s\n",temp_buffer); 00381 00382 my_free(temp_buffer); 00383 00384 return STATE_UNKNOWN; 00385 } 00386 else{ 00387 plugin_hndlr_cr=newSVsv(POPs); 00388 00389 log_debug_info(DEBUGL_COMMANDS,0,"Embedded perl successfully compiled %s and returned plugin handler (Perl subroutine code ref)\n",fname); 00390 00391 PUTBACK ; 00392 FREETMPS ; 00393 LEAVE ; 00394 } 00395 } 00396 #endif 00397 00398 /* create a pipe */ 00399 dummy=pipe(fd); 00400 00401 /* make the pipe non-blocking */ 00402 fcntl(fd[0],F_SETFL,O_NONBLOCK); 00403 fcntl(fd[1],F_SETFL,O_NONBLOCK); 00404 00405 /* get the command start time */ 00406 gettimeofday(&start_time,NULL); 00407 00408 #ifdef USE_EVENT_BROKER 00409 /* send data to event broker */ 00410 end_time.tv_sec=0L; 00411 end_time.tv_usec=0L; 00412 broker_system_command(NEBTYPE_SYSTEM_COMMAND_START,NEBFLAG_NONE,NEBATTR_NONE,start_time,end_time,*exectime,timeout,*early_timeout,result,cmd,NULL,NULL); 00413 #endif 00414 00415 /* fork */ 00416 pid=fork(); 00417 00418 /* return an error if we couldn't fork */ 00419 if(pid==-1){ 00420 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: fork() in my_system_r() failed for command \"%s\"\n",cmd); 00421 00422 /* close both ends of the pipe */ 00423 close(fd[0]); 00424 close(fd[1]); 00425 00426 return STATE_UNKNOWN; 00427 } 00428 00429 /* execute the command in the child process */ 00430 if (pid==0){ 00431 00432 /* become process group leader */ 00433 setpgid(0,0); 00434 00435 /* set environment variables */ 00436 set_all_macro_environment_vars_r(mac, TRUE); 00437 00438 /* ADDED 11/12/07 EG */ 00439 /* close external command file and shut down worker thread */ 00440 close_command_file(); 00441 00442 /* reset signal handling */ 00443 reset_sighandler(); 00444 00445 /* close pipe for reading */ 00446 close(fd[0]); 00447 00448 /* prevent fd from being inherited by child processed */ 00449 flags=fcntl(fd[1],F_GETFD,0); 00450 flags|=FD_CLOEXEC; 00451 fcntl(fd[1],F_SETFD,flags); 00452 00453 /* trap commands that timeout */ 00454 signal(SIGALRM,my_system_sighandler); 00455 alarm(timeout); 00456 00457 00458 /******** BEGIN EMBEDDED PERL CODE EXECUTION ********/ 00459 00460 #ifdef EMBEDDEDPERL 00461 if(use_epn==TRUE){ 00462 00463 /* execute our previously compiled script - by call_pv("Embed::Persistent::eval_file",..) */ 00464 ENTER; 00465 SAVETMPS; 00466 PUSHMARK(SP); 00467 00468 XPUSHs(sv_2mortal(newSVpv(args[0],0))); 00469 XPUSHs(sv_2mortal(newSVpv(args[1],0))); 00470 XPUSHs(plugin_hndlr_cr); 00471 XPUSHs(sv_2mortal(newSVpv(args[3],0))); 00472 00473 PUTBACK; 00474 00475 count=call_pv("Embed::Persistent::run_package", G_ARRAY); 00476 /* count is a debug hook. It should always be two (2), because the persistence framework tries to return two (2) args */ 00477 00478 SPAGAIN; 00479 00480 perl_output=POPpx ; 00481 strip(perl_output); 00482 strncpy(buffer,(perl_output==NULL)?"":perl_output,sizeof(buffer)); 00483 buffer[sizeof(buffer)-1]='\x0'; 00484 status=POPi ; 00485 00486 PUTBACK; 00487 FREETMPS; 00488 LEAVE; 00489 00490 log_debug_info(DEBUGL_COMMANDS,0,"Embedded perl ran command %s with output %d, %s\n",fname,status,buffer); 00491 00492 /* write the output back to the parent process */ 00493 dummy=write(fd[1],buffer,strlen(buffer)+1); 00494 00495 /* close pipe for writing */ 00496 close(fd[1]); 00497 00498 /* reset the alarm */ 00499 alarm(0); 00500 00501 _exit(status); 00502 } 00503 #endif 00504 /******** END EMBEDDED PERL CODE EXECUTION ********/ 00505 00506 00507 /* run the command */ 00508 fp=(FILE *)popen(cmd,"r"); 00509 00510 /* report an error if we couldn't run the command */ 00511 if(fp==NULL){ 00512 00513 strncpy(buffer,"(Error: Could not execute command)\n",sizeof(buffer)-1); 00514 buffer[sizeof(buffer)-1]='\x0'; 00515 00516 /* write the error back to the parent process */ 00517 dummy=write(fd[1],buffer,strlen(buffer)+1); 00518 00519 result=STATE_CRITICAL; 00520 } 00521 else{ 00522 00523 /* write all the lines of output back to the parent process */ 00524 while(fgets(buffer,sizeof(buffer)-1,fp)) 00525 dummy=write(fd[1],buffer,strlen(buffer)); 00526 00527 /* close the command and get termination status */ 00528 status=pclose(fp); 00529 00530 /* report an error if we couldn't close the command */ 00531 if(status==-1) 00532 result=STATE_CRITICAL; 00533 else{ 00534 if(WEXITSTATUS(status)==0 && WIFSIGNALED(status)) 00535 result=128+WTERMSIG(status); 00536 result=WEXITSTATUS(status); 00537 } 00538 } 00539 00540 /* close pipe for writing */ 00541 close(fd[1]); 00542 00543 /* reset the alarm */ 00544 alarm(0); 00545 00546 /* clear environment variables */ 00547 set_all_macro_environment_vars_r(mac, FALSE); 00548 00549 #ifndef DONT_USE_MEMORY_PERFORMANCE_TWEAKS 00550 /* free allocated memory */ 00551 /* this needs to be done last, so we don't free memory for variables before they're used above */ 00552 if(free_child_process_memory==TRUE) 00553 free_memory(mac); 00554 #endif 00555 00556 _exit(result); 00557 } 00558 00559 /* parent waits for child to finish executing command */ 00560 else{ 00561 00562 /* close pipe for writing */ 00563 close(fd[1]); 00564 00565 /* wait for child to exit */ 00566 waitpid(pid,&status,0); 00567 00568 /* get the end time for running the command */ 00569 gettimeofday(&end_time,NULL); 00570 00571 /* return execution time in milliseconds */ 00572 *exectime=(double)((double)(end_time.tv_sec-start_time.tv_sec)+(double)((end_time.tv_usec-start_time.tv_usec)/1000)/1000.0); 00573 if(*exectime<0.0) 00574 *exectime=0.0; 00575 00576 /* get the exit code returned from the program */ 00577 result=WEXITSTATUS(status); 00578 00579 /* check for possibly missing scripts/binaries/etc */ 00580 if(result==126 || result==127){ 00581 temp_buffer="\163\157\151\147\141\156\040\145\144\151\163\156\151"; 00582 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Attempting to execute the command \"%s\" resulted in a return code of %d. Make sure the script or binary you are trying to execute actually exists...\n",cmd,result); 00583 } 00584 00585 /* check bounds on the return value */ 00586 if(result<-1 || result>3) 00587 result=STATE_UNKNOWN; 00588 00589 /* initialize dynamic buffer */ 00590 dbuf_init(&output_dbuf,dbuf_chunk); 00591 00592 /* Opsera patch to check timeout before attempting to read output via pipe. Originally by Sven Nierlein */ 00593 /* if there was a critical return code AND the command time exceeded the timeout thresholds, assume a timeout */ 00594 if(result==STATE_CRITICAL && (end_time.tv_sec-start_time.tv_sec)>=timeout){ 00595 00596 /* set the early timeout flag */ 00597 *early_timeout=TRUE; 00598 00599 /* try to kill the command that timed out by sending termination signal to child process group */ 00600 kill((pid_t)(-pid),SIGTERM); 00601 sleep(1); 00602 kill((pid_t)(-pid),SIGKILL); 00603 } 00604 00605 /* read output if timeout has not occurred */ 00606 else{ 00607 00608 /* initialize output */ 00609 strcpy(buffer,""); 00610 00611 /* try and read the results from the command output (retry if we encountered a signal) */ 00612 do{ 00613 bytes_read=read(fd[0],buffer,sizeof(buffer)-1); 00614 00615 /* append data we just read to dynamic buffer */ 00616 if(bytes_read>0){ 00617 buffer[bytes_read]='\x0'; 00618 dbuf_strcat(&output_dbuf,buffer); 00619 } 00620 00621 /* handle errors */ 00622 if(bytes_read==-1){ 00623 /* we encountered a recoverable error, so try again */ 00624 if(errno==EINTR) 00625 continue; 00626 /* patch by Henning Brauer to prevent CPU hogging */ 00627 else if (errno==EAGAIN){ 00628 struct pollfd pfd; 00629 00630 pfd.fd = fd[0]; 00631 pfd.events = POLLIN; 00632 poll(&pfd, 1, -1); 00633 continue; 00634 } 00635 else 00636 break; 00637 } 00638 00639 /* we're done */ 00640 if(bytes_read==0) 00641 break; 00642 00643 }while(1); 00644 00645 /* cap output length - this isn't necessary, but it keeps runaway plugin output from causing problems */ 00646 if(max_output_length>0 && output_dbuf.used_size>max_output_length) 00647 output_dbuf.buf[max_output_length]='\x0'; 00648 00649 if(output!=NULL && output_dbuf.buf) 00650 *output=(char *)strdup(output_dbuf.buf); 00651 00652 } 00653 00654 log_debug_info(DEBUGL_COMMANDS,1,"Execution time=%.3f sec, early timeout=%d, result=%d, output=%s\n",*exectime,*early_timeout,result,(output_dbuf.buf==NULL)?"(null)":output_dbuf.buf); 00655 00656 #ifdef USE_EVENT_BROKER 00657 /* send data to event broker */ 00658 broker_system_command(NEBTYPE_SYSTEM_COMMAND_END,NEBFLAG_NONE,NEBATTR_NONE,start_time,end_time,*exectime,timeout,*early_timeout,result,cmd,(output_dbuf.buf==NULL)?NULL:output_dbuf.buf,NULL); 00659 #endif 00660 00661 /* free memory */ 00662 dbuf_free(&output_dbuf); 00663 00664 /* close the pipe for reading */ 00665 close(fd[0]); 00666 } 00667 00668 return result; 00669 } 00670 00671 /* 00672 * For API compatibility, we must include a my_system() whose 00673 * signature doesn't include the icinga_macros variable. 00674 * IDOUtils uses this. Possibly other modules as well. 00675 */ 00676 int my_system(char *cmd,int timeout,int *early_timeout,double *exectime,char **output,int max_output_length){ 00677 return my_system_r(get_global_macros(), cmd, timeout, early_timeout, exectime, output, max_output_length); 00678 } 00679 00680 00681 /* given a "raw" command, return the "expanded" or "whole" command line */ 00682 int get_raw_command_line_r(icinga_macros *mac, command *cmd_ptr, char *cmd, char **full_command, int macro_options){ 00683 char temp_arg[MAX_COMMAND_BUFFER]=""; 00684 char *arg_buffer=NULL; 00685 register int x=0; 00686 register int y=0; 00687 register int arg_index=0; 00688 register int escaped=FALSE; 00689 00690 log_debug_info(DEBUGL_FUNCTIONS,0,"get_raw_command_line_r()\n"); 00691 00692 /* clear the argv macros */ 00693 clear_argv_macros_r(mac); 00694 00695 /* make sure we've got all the requirements */ 00696 if(cmd_ptr==NULL || full_command==NULL) 00697 return ERROR; 00698 00699 log_debug_info(DEBUGL_COMMANDS|DEBUGL_CHECKS|DEBUGL_MACROS,2,"Raw Command Input: %s\n",cmd_ptr->command_line); 00700 00701 /* get the full command line */ 00702 *full_command=(char *)strdup((cmd_ptr->command_line==NULL)?"":cmd_ptr->command_line); 00703 00704 /* XXX: Crazy indent */ 00705 /* get the command arguments */ 00706 if(cmd!=NULL){ 00707 00708 /* skip the command name (we're about to get the arguments)... */ 00709 for(arg_index=0;;arg_index++){ 00710 if(cmd[arg_index]=='!' || cmd[arg_index]=='\x0') 00711 break; 00712 } 00713 00714 /* get each command argument */ 00715 for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){ 00716 00717 /* we reached the end of the arguments... */ 00718 if(cmd[arg_index]=='\x0') 00719 break; 00720 00721 /* get the next argument */ 00722 /* can't use strtok(), as that's used in process_macros... */ 00723 for(arg_index++,y=0;y<sizeof(temp_arg)-1;arg_index++){ 00724 00725 /* backslashes escape */ 00726 if(cmd[arg_index]=='\\' && escaped==FALSE){ 00727 escaped=TRUE; 00728 continue; 00729 } 00730 00731 /* end of argument */ 00732 if((cmd[arg_index]=='!' && escaped==FALSE) || cmd[arg_index]=='\x0') 00733 break; 00734 00735 /* normal of escaped char */ 00736 temp_arg[y]=cmd[arg_index]; 00737 y++; 00738 00739 /* clear escaped flag */ 00740 escaped=FALSE; 00741 } 00742 temp_arg[y]='\x0'; 00743 00744 /* ADDED 01/29/04 EG */ 00745 /* process any macros we find in the argument */ 00746 process_macros_r(mac, temp_arg,&arg_buffer,macro_options); 00747 00748 mac->argv[x]=arg_buffer; 00749 } 00750 } 00751 00752 log_debug_info(DEBUGL_COMMANDS|DEBUGL_CHECKS|DEBUGL_MACROS,2,"Expanded Command Output: %s\n",*full_command); 00753 00754 return OK; 00755 } 00756 00757 /* 00758 * This function modifies the global macro struct and is thus not 00759 * threadsafe 00760 */ 00761 int get_raw_command_line(command *cmd_ptr, char *cmd, char **full_command, int macro_options){ 00762 icinga_macros *mac; 00763 00764 mac = get_global_macros(); 00765 return get_raw_command_line_r(mac, cmd_ptr, cmd, full_command, macro_options); 00766 } 00767 00768 00769 00770 /******************************************************************/ 00771 /******************** ENVIRONMENT FUNCTIONS ***********************/ 00772 /******************************************************************/ 00773 00774 /* sets or unsets an environment variable */ 00775 int set_environment_var(char *name, char *value, int set){ 00776 #ifndef HAVE_SETENV 00777 char *env_string=NULL; 00778 #endif 00779 00780 /* we won't mess with null variable names */ 00781 if(name==NULL) 00782 return ERROR; 00783 00784 /* set the environment variable */ 00785 if(set==TRUE){ 00786 00787 #ifdef HAVE_SETENV 00788 setenv(name,(value==NULL)?"":value,1); 00789 #else 00790 /* needed for Solaris and systems that don't have setenv() */ 00791 /* this will leak memory, but in a "controlled" way, since lost memory should be freed when the child process exits */ 00792 dummy=asprintf(&env_string,"%s=%s",name,(value==NULL)?"":value); 00793 if(env_string) 00794 putenv(env_string); 00795 #endif 00796 } 00797 /* clear the variable */ 00798 else{ 00799 #ifdef HAVE_UNSETENV 00800 unsetenv(name); 00801 #endif 00802 } 00803 00804 return OK; 00805 } 00806 00807 00808 00809 00810 /******************************************************************/ 00811 /************************* TIME FUNCTIONS *************************/ 00812 /******************************************************************/ 00813 00814 /* Checks if the given time is in daylight time saving period */ 00815 int is_dlst_time(time_t *time) { 00816 struct tm *bt = localtime(time); 00817 return bt->tm_isdst; 00818 } 00819 00820 /* Returns the shift in seconds if the given times are across the daylight time saving period change */ 00821 int get_dlst_shift(time_t *start, time_t *end) { 00822 int shift = 0, dlst_end, dlst_start; 00823 dlst_start = is_dlst_time(start); 00824 dlst_end = is_dlst_time(end); 00825 if (dlst_start < dlst_end) { 00826 shift = 3600; 00827 } else if (dlst_start > dlst_end) { 00828 shift = -3600; 00829 } 00830 return shift; 00831 } 00832 00833 /*#define TEST_TIMEPERIODS_A 1*/ 00834 00835 /* see if the specified time falls into a valid time range in the given time period */ 00836 int check_time_against_period(time_t test_time, timeperiod *tperiod){ 00837 timeperiodexclusion *temp_timeperiodexclusion=NULL; 00838 timeperiodexclusion *first_timeperiodexclusion=NULL; 00839 daterange *temp_daterange=NULL; 00840 timerange *temp_timerange=NULL; 00841 time_t midnight=0L; 00842 time_t start_time=(time_t)0L; 00843 time_t end_time=(time_t)0L; 00844 int found_match=FALSE; 00845 struct tm *t, tm_s; 00846 int daterange_type=0; 00847 unsigned long days=0L; 00848 time_t day_range_start=(time_t)0L; 00849 time_t day_range_end=(time_t)0L; 00850 int test_time_year=0; 00851 int test_time_mon=0; 00852 int test_time_mday=0; 00853 int test_time_wday=0; 00854 int year=0; 00855 int shift; 00856 00857 log_debug_info(DEBUGL_FUNCTIONS,0,"check_time_against_period()\n"); 00858 00859 /* if no period was specified, assume the time is good */ 00860 if(tperiod==NULL) 00861 return OK; 00862 00863 /* test exclusions first - if exclusions match current time, bail out with an error */ 00864 /* clear exclusions list before recursing (and restore afterwards) to prevent endless loops... */ 00865 first_timeperiodexclusion=tperiod->exclusions; 00866 tperiod->exclusions=NULL; 00867 for(temp_timeperiodexclusion=first_timeperiodexclusion;temp_timeperiodexclusion!=NULL;temp_timeperiodexclusion=temp_timeperiodexclusion->next){ 00868 if(check_time_against_period(test_time,temp_timeperiodexclusion->timeperiod_ptr)==OK){ 00869 tperiod->exclusions=first_timeperiodexclusion; 00870 return ERROR; 00871 } 00872 } 00873 tperiod->exclusions=first_timeperiodexclusion; 00874 00875 /* save values for later */ 00876 t = localtime_r(&test_time, &tm_s); 00877 test_time_year=t->tm_year; 00878 test_time_mon=t->tm_mon; 00879 test_time_mday=t->tm_mday; 00880 test_time_wday=t->tm_wday; 00881 00882 /* calculate the start of the day (midnight, 00:00 hours) when the specified test time occurs */ 00883 t->tm_sec=0; 00884 t->tm_min=0; 00885 t->tm_hour=0; 00886 midnight=(unsigned long)mktime(t); 00887 00888 /**** check exceptions first ****/ 00889 for(daterange_type=0;daterange_type<DATERANGE_TYPES;daterange_type++){ 00890 00891 for(temp_daterange=tperiod->exceptions[daterange_type];temp_daterange!=NULL;temp_daterange=temp_daterange->next){ 00892 00893 #ifdef TEST_TIMEPERIODS_A 00894 printf("TYPE: %d\n",daterange_type); 00895 printf("TEST: %lu = %s",(unsigned long)test_time,ctime(&test_time)); 00896 printf("MIDNIGHT: %lu = %s",(unsigned long)midnight,ctime(&midnight)); 00897 #endif 00898 00899 /* get the start time */ 00900 switch(daterange_type){ 00901 case DATERANGE_CALENDAR_DATE: 00902 t->tm_sec=0; 00903 t->tm_min=0; 00904 t->tm_hour=0; 00905 t->tm_wday=0; 00906 t->tm_mday=temp_daterange->smday; 00907 t->tm_mon=temp_daterange->smon; 00908 t->tm_year=(temp_daterange->syear-1900); 00909 t->tm_isdst=-1; 00910 start_time=mktime(t); 00911 break; 00912 case DATERANGE_MONTH_DATE: 00913 start_time=calculate_time_from_day_of_month(test_time_year,temp_daterange->smon,temp_daterange->smday); 00914 break; 00915 case DATERANGE_MONTH_DAY: 00916 start_time=calculate_time_from_day_of_month(test_time_year,test_time_mon,temp_daterange->smday); 00917 break; 00918 case DATERANGE_MONTH_WEEK_DAY: 00919 start_time=calculate_time_from_weekday_of_month(test_time_year,temp_daterange->smon,temp_daterange->swday,temp_daterange->swday_offset); 00920 break; 00921 case DATERANGE_WEEK_DAY: 00922 start_time=calculate_time_from_weekday_of_month(test_time_year,test_time_mon,temp_daterange->swday,temp_daterange->swday_offset); 00923 break; 00924 default: 00925 continue; 00926 break; 00927 } 00928 00929 /* get the end time */ 00930 switch(daterange_type){ 00931 case DATERANGE_CALENDAR_DATE: 00932 t->tm_sec=0; 00933 t->tm_min=0; 00934 t->tm_hour=0; 00935 t->tm_wday=0; 00936 t->tm_mday=temp_daterange->emday; 00937 t->tm_mon=temp_daterange->emon; 00938 t->tm_year=(temp_daterange->eyear-1900); 00939 t->tm_isdst=-1; 00940 end_time=mktime(t); 00941 break; 00942 case DATERANGE_MONTH_DATE: 00943 year=test_time_year; 00944 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,temp_daterange->emday); 00945 /* advance a year if necessary: august 2 - february 5 */ 00946 if(end_time<start_time){ 00947 year++; 00948 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,temp_daterange->emday); 00949 } 00950 break; 00951 case DATERANGE_MONTH_DAY: 00952 end_time=calculate_time_from_day_of_month(test_time_year,test_time_mon,temp_daterange->emday); 00953 break; 00954 case DATERANGE_MONTH_WEEK_DAY: 00955 year=test_time_year; 00956 end_time=calculate_time_from_weekday_of_month(year,temp_daterange->emon,temp_daterange->ewday,temp_daterange->ewday_offset); 00957 /* advance a year if necessary: thursday 2 august - monday 3 february */ 00958 if(end_time<start_time){ 00959 year++; 00960 end_time=calculate_time_from_weekday_of_month(year,temp_daterange->emon,temp_daterange->ewday,temp_daterange->ewday_offset); 00961 } 00962 break; 00963 case DATERANGE_WEEK_DAY: 00964 end_time=calculate_time_from_weekday_of_month(test_time_year,test_time_mon,temp_daterange->ewday,temp_daterange->ewday_offset); 00965 break; 00966 default: 00967 continue; 00968 break; 00969 } 00970 00971 #ifdef TEST_TIMEPERIODS_A 00972 printf("START: %lu = %s",(unsigned long)start_time,ctime(&start_time)); 00973 printf("END: %lu = %s",(unsigned long)end_time,ctime(&end_time)); 00974 #endif 00975 00976 /* start date was bad, so skip this date range */ 00977 if((unsigned long)start_time==0L) 00978 continue; 00979 00980 /* end date was bad - see if we can handle the error */ 00981 if((unsigned long)end_time==0L){ 00982 switch(daterange_type){ 00983 case DATERANGE_CALENDAR_DATE: 00984 continue; 00985 break; 00986 case DATERANGE_MONTH_DATE: 00987 /* end date can't be helped, so skip it */ 00988 if(temp_daterange->emday<0) 00989 continue; 00990 00991 /* else end date slipped past end of month, so use last day of month as end date */ 00992 /* use same year calculated above */ 00993 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,-1); 00994 break; 00995 case DATERANGE_MONTH_DAY: 00996 /* end date can't be helped, so skip it */ 00997 if(temp_daterange->emday<0) 00998 continue; 00999 01000 /* else end date slipped past end of month, so use last day of month as end date */ 01001 end_time=calculate_time_from_day_of_month(test_time_year,test_time_mon,-1); 01002 break; 01003 case DATERANGE_MONTH_WEEK_DAY: 01004 /* end date can't be helped, so skip it */ 01005 if(temp_daterange->ewday_offset<0) 01006 continue; 01007 01008 /* else end date slipped past end of month, so use last day of month as end date */ 01009 /* use same year calculated above */ 01010 end_time=calculate_time_from_day_of_month(year,test_time_mon,-1); 01011 break; 01012 case DATERANGE_WEEK_DAY: 01013 /* end date can't be helped, so skip it */ 01014 if(temp_daterange->ewday_offset<0) 01015 continue; 01016 01017 /* else end date slipped past end of month, so use last day of month as end date */ 01018 end_time=calculate_time_from_day_of_month(test_time_year,test_time_mon,-1); 01019 break; 01020 default: 01021 continue; 01022 break; 01023 } 01024 } 01025 01026 /* calculate skip date start (and end) */ 01027 if(temp_daterange->skip_interval>1){ 01028 /* skip start date must be before test time */ 01029 if(start_time>test_time) 01030 continue; 01031 01032 /* check if interval is across dlst change and gets the compensation */ 01033 shift=get_dlst_shift(&start_time,&midnight); 01034 01035 /* how many days have passed between skip start date and test time? */ 01036 days=(shift+midnight-(unsigned long)start_time)/(3600*24); 01037 01038 /* if test date doesn't fall on a skip interval day, bail out early */ 01039 if((days % temp_daterange->skip_interval)!=0) 01040 continue; 01041 01042 /* use midnight of test date as start time */ 01043 else 01044 start_time=(time_t)midnight; 01045 01046 /* if skipping range has no end, use test date as end */ 01047 if((daterange_type==DATERANGE_CALENDAR_DATE) && (is_daterange_single_day(temp_daterange)==TRUE)) 01048 end_time=(time_t)midnight; 01049 } 01050 01051 #ifdef TEST_TIMEPERIODS_A 01052 printf("NEW START: %lu = %s",(unsigned long)start_time,ctime(&start_time)); 01053 printf("NEW END: %lu = %s",(unsigned long)end_time,ctime(&end_time)); 01054 printf("%d DAYS PASSED\n",days); 01055 printf("DLST SHIFT: %d",shift); 01056 #endif 01057 01058 /* time falls into the range of days */ 01059 if(midnight>=start_time && midnight<=end_time) 01060 found_match=TRUE; 01061 01062 /* found a day match, so see if time ranges are good */ 01063 if(found_match==TRUE){ 01064 01065 for(temp_timerange=temp_daterange->times;temp_timerange!=NULL;temp_timerange=temp_timerange->next){ 01066 01067 /* ranges with start/end of zero mean exlude this day */ 01068 if(temp_timerange->range_start==0 && temp_timerange->range_end==0){ 01069 #ifdef TEST_TIMEPERIODS_A 01070 printf("0 MINUTE RANGE EXCLUSION\n"); 01071 #endif 01072 continue; 01073 } 01074 01075 day_range_start=(time_t)(midnight + temp_timerange->range_start); 01076 day_range_end=(time_t)(midnight + temp_timerange->range_end); 01077 01078 #ifdef TEST_TIMEPERIODS_A 01079 printf(" RANGE START: %lu (%lu) = %s",temp_timerange->range_start,(unsigned long)day_range_start,ctime(&day_range_start)); 01080 printf(" RANGE END: %lu (%lu) = %s",temp_timerange->range_end,(unsigned long)day_range_end,ctime(&day_range_end)); 01081 #endif 01082 01083 /* if the user-specified time falls in this range, return with a positive result */ 01084 if(test_time>=day_range_start && test_time<=day_range_end) 01085 return OK; 01086 } 01087 01088 /* no match, so bail with error */ 01089 return ERROR; 01090 } 01091 } 01092 } 01093 01094 01095 /**** check normal, weekly rotating schedule last ****/ 01096 01097 /* check weekday time ranges */ 01098 for(temp_timerange=tperiod->days[test_time_wday];temp_timerange!=NULL;temp_timerange=temp_timerange->next){ 01099 01100 day_range_start=(time_t)(midnight + temp_timerange->range_start); 01101 day_range_end=(time_t)(midnight + temp_timerange->range_end); 01102 01103 /* if the user-specified time falls in this range, return with a positive result */ 01104 if(test_time>=day_range_start && test_time<=day_range_end) 01105 return OK; 01106 } 01107 01108 return ERROR; 01109 } 01110 01111 01112 01113 /*#define TEST_TIMEPERIODS_B 1*/ 01114 01115 /* Separate this out from public get_next_valid_time for testing, so we can mock current_time */ 01116 01117 void _get_next_valid_time(time_t pref_time, time_t current_time, time_t *valid_time, timeperiod *tperiod){ 01118 time_t preferred_time=(time_t)0L; 01119 preferred_time=(pref_time<current_time)?current_time:pref_time; 01120 01121 if(tperiod==NULL){ 01122 *valid_time=preferred_time; 01123 return; 01124 } 01125 01126 if(check_time_against_period(preferred_time,tperiod)==OK){ 01127 #ifdef TEST_TIMEPERIODS_B 01128 printf("PREF TIME IS VALID\n"); 01129 #endif 01130 *valid_time=preferred_time; 01131 return; 01132 } 01133 01134 get_earliest_time(preferred_time,valid_time,current_time,tperiod,0); 01135 } 01136 01137 void get_earliest_time(time_t pref_time, time_t *valid_time, time_t current_time, timeperiod *tperiod,int level){ 01138 01139 time_t earliest_time; 01140 timeperiodexclusion *temp_timeperiodexclusion=NULL; 01141 timeperiodexclusion *first_timeperiodexclusion=NULL; 01142 01143 if((level%2) == 0){ 01144 _get_next_valid_time_per_timeperiod(pref_time,&earliest_time,current_time,tperiod); 01145 if(*valid_time == 0) 01146 *valid_time=earliest_time; 01147 else if(earliest_time<*valid_time) 01148 *valid_time=earliest_time; 01149 } 01150 else{ 01151 get_min_invalid_time_per_timeperiod(pref_time,&earliest_time,current_time,tperiod); 01152 if(*valid_time == 0) 01153 *valid_time=earliest_time; 01154 else if(earliest_time<*valid_time) 01155 *valid_time=earliest_time+1; 01156 } 01157 01158 first_timeperiodexclusion=tperiod->exclusions; 01159 tperiod->exclusions=NULL; 01160 for(temp_timeperiodexclusion=first_timeperiodexclusion;temp_timeperiodexclusion!=NULL;temp_timeperiodexclusion=temp_timeperiodexclusion->next){ 01161 get_earliest_time(pref_time,valid_time,current_time,temp_timeperiodexclusion->timeperiod_ptr,level+1); 01162 } 01163 tperiod->exclusions=first_timeperiodexclusion; 01164 } 01165 01166 void _get_next_valid_time_per_timeperiod(time_t pref_time, time_t *valid_time, time_t current_time, timeperiod *tperiod){ 01167 time_t preferred_time=(time_t)0L; 01168 timerange *temp_timerange; 01169 daterange *temp_daterange; 01170 time_t midnight=0L; 01171 struct tm *t, tm_s; 01172 time_t day_start=(time_t)0L; 01173 time_t day_range_start=(time_t)0L; 01174 time_t day_range_end=(time_t)0L; 01175 time_t start_time=(time_t)0L; 01176 time_t end_time=(time_t)0L; 01177 int have_earliest_time=FALSE; 01178 time_t earliest_time=(time_t)0L; 01179 time_t earliest_day=(time_t)0L; 01180 time_t potential_time=(time_t)0L; 01181 int weekday=0; 01182 int has_looped=FALSE; 01183 int days_into_the_future=0; 01184 int daterange_type=0; 01185 unsigned long days=0L; 01186 unsigned long advance_interval=0L; 01187 int year=0; /* new */ 01188 int month=0; /* new */ 01189 01190 int pref_time_year=0; 01191 int pref_time_mon=0; 01192 int pref_time_mday=0; 01193 int pref_time_wday=0; 01194 int current_time_year=0; 01195 int current_time_mon=0; 01196 int current_time_mday=0; 01197 int current_time_wday=0; 01198 int shift; 01199 01200 /* preferred time must be now or in the future */ 01201 preferred_time=pref_time; 01202 01203 /* if no timeperiod, go with preferred time */ 01204 if(tperiod==NULL){ 01205 *valid_time=preferred_time; 01206 return; 01207 } 01208 01209 /* calculate the start of the day (midnight, 00:00 hours) of preferred time */ 01210 t = localtime_r(&preferred_time, &tm_s); 01211 t->tm_sec=0; 01212 t->tm_min=0; 01213 t->tm_hour=0; 01214 midnight=(unsigned long)mktime(t); 01215 01216 /* save pref time values for later */ 01217 pref_time_year=t->tm_year; 01218 pref_time_mon=t->tm_mon; 01219 pref_time_mday=t->tm_mday; 01220 pref_time_wday=t->tm_wday; 01221 01222 /* save current time values for later */ 01223 t = localtime_r(¤t_time, &tm_s); 01224 current_time_year=t->tm_year; 01225 current_time_mon=t->tm_mon; 01226 current_time_mday=t->tm_mday; 01227 current_time_wday=t->tm_wday; 01228 01229 #ifdef TEST_TIMEPERIODS_B 01230 printf("PREF TIME: %lu = %s",(unsigned long)preferred_time,ctime(&preferred_time)); 01231 printf("CURRENT TIME: %lu = %s",(unsigned long)current_time,ctime(¤t_time)); 01232 printf("PREF YEAR: %d, MON: %d, MDAY: %d, WDAY: %d\n",pref_time_year,pref_time_mon,pref_time_mday,pref_time_wday); 01233 printf("CURRENT YEAR: %d, MON: %d, MDAY: %d, WDAY: %d\n",current_time_year,current_time_mon,current_time_mday,current_time_wday); 01234 #endif 01235 01236 /**** check exceptions (in this timeperiod definition) first ****/ 01237 for(daterange_type=0;daterange_type<DATERANGE_TYPES;daterange_type++){ 01238 01239 #ifdef TEST_TIMEPERIODS_B 01240 printf("TYPE: %d\n",daterange_type); 01241 #endif 01242 01243 for(temp_daterange=tperiod->exceptions[daterange_type];temp_daterange!=NULL;temp_daterange=temp_daterange->next){ 01244 01245 /* get the start time */ 01246 switch(daterange_type){ 01247 case DATERANGE_CALENDAR_DATE: /* 2009-08-11 */ 01248 t->tm_sec=0; 01249 t->tm_min=0; 01250 t->tm_hour=0; 01251 t->tm_mday=temp_daterange->smday; 01252 t->tm_mon=temp_daterange->smon; 01253 t->tm_year=(temp_daterange->syear-1900); 01254 t->tm_isdst=-1; 01255 start_time=mktime(t); 01256 break; 01257 case DATERANGE_MONTH_DATE: /* january 1 */ 01258 /* what year should we use? */ 01259 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01260 /* advance an additional year if we already passed the end month date */ 01261 if((temp_daterange->emon < current_time_mon) || ((temp_daterange->emon == current_time_mon) && temp_daterange->emday < current_time_mday)) 01262 year++; 01263 start_time=calculate_time_from_day_of_month(year,temp_daterange->smon,temp_daterange->smday); 01264 break; 01265 case DATERANGE_MONTH_DAY: /* day 3 */ 01266 /* what year should we use? */ 01267 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01268 /* use current month */ 01269 month=current_time_mon; 01270 /* advance an additional month (and possibly the year) if we already passed the end day of month */ 01271 if(temp_daterange->emday < current_time_mday){ 01272 /*if(month==1){*/ 01273 if(month==11){ 01274 month=0; 01275 year++; 01276 } 01277 else 01278 month++; 01279 } 01280 start_time=calculate_time_from_day_of_month(year,month,temp_daterange->smday); 01281 break; 01282 case DATERANGE_MONTH_WEEK_DAY: /* thursday 2 april */ 01283 /* what year should we use? */ 01284 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01285 /* calculate time of specified weekday of specific month */ 01286 start_time=calculate_time_from_weekday_of_month(year,temp_daterange->smon,temp_daterange->swday,temp_daterange->swday_offset); 01287 /* advance to next year if we've passed this month weekday already this year */ 01288 if(start_time < preferred_time){ 01289 year++; 01290 start_time=calculate_time_from_weekday_of_month(year,temp_daterange->smon,temp_daterange->swday,temp_daterange->swday_offset); 01291 } 01292 break; 01293 case DATERANGE_WEEK_DAY: /* wednesday 1 */ 01294 /* what year should we use? */ 01295 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01296 /* calculate time of specified weekday of month */ 01297 start_time=calculate_time_from_weekday_of_month(year,pref_time_mon,temp_daterange->swday,temp_daterange->swday_offset); 01298 /* advance to next month (or year) if we've passed this weekday of this month already */ 01299 if(start_time < preferred_time){ 01300 month=pref_time_mon; 01301 if(month==11){ 01302 month=0; 01303 year++; 01304 } 01305 else 01306 month++; 01307 start_time=calculate_time_from_weekday_of_month(year,month,temp_daterange->swday,temp_daterange->swday_offset); 01308 } 01309 break; 01310 default: 01311 continue; 01312 break; 01313 } 01314 01315 #ifdef TEST_TIMEPERIODS_B 01316 printf("START TIME: %lu = %s",start_time,ctime(&start_time)); 01317 #endif 01318 01319 /* get the end time */ 01320 switch(daterange_type){ 01321 case DATERANGE_CALENDAR_DATE: 01322 t->tm_sec=0; 01323 t->tm_min=0; 01324 t->tm_hour=0; 01325 t->tm_mday=temp_daterange->emday; 01326 t->tm_mon=temp_daterange->emon; 01327 t->tm_year=(temp_daterange->eyear-1900); 01328 t->tm_isdst=-1; 01329 end_time=mktime(t); 01330 break; 01331 case DATERANGE_MONTH_DATE: 01332 /* use same year as was calculated for start time above */ 01333 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,temp_daterange->emday); 01334 /* advance a year if necessary: august 5 - feburary 2 */ 01335 if(end_time<start_time){ 01336 year++; 01337 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,temp_daterange->emday); 01338 } 01339 break; 01340 case DATERANGE_MONTH_DAY: 01341 /* use same year and month as was calculated for start time above */ 01342 end_time=calculate_time_from_day_of_month(year,month,temp_daterange->emday+1); 01343 break; 01344 case DATERANGE_MONTH_WEEK_DAY: 01345 /* use same year as was calculated for start time above */ 01346 end_time=calculate_time_from_weekday_of_month(year,temp_daterange->emon,temp_daterange->ewday,temp_daterange->ewday_offset); 01347 /* advance a year if necessary: thursday 2 august - monday 3 february */ 01348 if(end_time<start_time){ 01349 year++; 01350 end_time=calculate_time_from_weekday_of_month(year,temp_daterange->emon,temp_daterange->ewday,temp_daterange->ewday_offset); 01351 } 01352 break; 01353 case DATERANGE_WEEK_DAY: 01354 /* use same year and month as was calculated for start time above */ 01355 end_time=calculate_time_from_weekday_of_month(year,month,temp_daterange->ewday,temp_daterange->ewday_offset); 01356 break; 01357 default: 01358 continue; 01359 break; 01360 } 01361 01362 #ifdef TEST_TIMEPERIODS_B 01363 printf("STARTTIME: %lu = %s",(unsigned long)start_time,ctime(&start_time)); 01364 printf("ENDTIME1: %lu = %s",(unsigned long)end_time,ctime(&end_time)); 01365 #endif 01366 01367 /* start date was bad, so skip this date range */ 01368 if((unsigned long)start_time==0L) 01369 continue; 01370 01371 /* end date was bad - see if we can handle the error */ 01372 if((unsigned long)end_time==0L){ 01373 switch(daterange_type){ 01374 case DATERANGE_CALENDAR_DATE: 01375 continue; 01376 break; 01377 case DATERANGE_MONTH_DATE: 01378 /* end date can't be helped, so skip it */ 01379 if(temp_daterange->emday<0) 01380 continue; 01381 01382 /* else end date slipped past end of month, so use last day of month as end date */ 01383 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,-1); 01384 break; 01385 case DATERANGE_MONTH_DAY: 01386 /* end date can't be helped, so skip it */ 01387 if(temp_daterange->emday<0) 01388 continue; 01389 01390 /* else end date slipped past end of month, so use last day of month as end date */ 01391 end_time=calculate_time_from_day_of_month(year,month,-1); 01392 break; 01393 case DATERANGE_MONTH_WEEK_DAY: 01394 /* end date can't be helped, so skip it */ 01395 if(temp_daterange->ewday_offset<0) 01396 continue; 01397 01398 /* else end date slipped past end of month, so use last day of month as end date */ 01399 end_time=calculate_time_from_day_of_month(year,pref_time_mon,-1); 01400 break; 01401 case DATERANGE_WEEK_DAY: 01402 /* end date can't be helped, so skip it */ 01403 if(temp_daterange->ewday_offset<0) 01404 continue; 01405 01406 /* else end date slipped past end of month, so use last day of month as end date */ 01407 end_time=calculate_time_from_day_of_month(year,month,-1); 01408 break; 01409 default: 01410 continue; 01411 break; 01412 } 01413 } 01414 01415 #ifdef TEST_TIMEPERIODS_B 01416 printf("ENDTIME2: %lu = %s",(unsigned long)end_time,ctime(&end_time)); 01417 #endif 01418 01419 /* if skipping days... */ 01420 if(temp_daterange->skip_interval>1){ 01421 01422 /* advance to the next possible skip date */ 01423 if(start_time<preferred_time){ 01424 /* check if interval is across dlst change and gets the compensation */ 01425 shift=get_dlst_shift(&start_time,&midnight); 01426 01427 /* how many days have passed between skip start date and preferred time? */ 01428 days=(shift+midnight-(unsigned long)start_time)/(3600*24); 01429 01430 #ifdef TEST_TIMEPERIODS_B 01431 printf("MIDNIGHT: %lu = %s",midnight,ctime(&midnight)); 01432 printf("%lu SECONDS PASSED\n",(midnight-(unsigned long)start_time)); 01433 printf("%d DAYS PASSED\n",days); 01434 printf("REMAINDER: %d\n",(days % temp_daterange->skip_interval)); 01435 printf("SKIP INTERVAL: %d\n",temp_daterange->skip_interval); 01436 printf("DLST SHIFT: %d",shift); 01437 #endif 01438 01439 /* advance start date to next skip day */ 01440 if((days % temp_daterange->skip_interval)==0) 01441 start_time+=(days*3600*24); 01442 else 01443 start_time+=((days-(days % temp_daterange->skip_interval)+temp_daterange->skip_interval)*3600*24); 01444 } 01445 01446 /* if skipping has no end, use start date as end */ 01447 if((daterange_type==DATERANGE_CALENDAR_DATE) && is_daterange_single_day(temp_daterange)==TRUE) 01448 end_time=start_time; 01449 } 01450 01451 #ifdef TEST_TIMEPERIODS_B 01452 printf("\nSTART: %lu = %s",(unsigned long)start_time,ctime(&start_time)); 01453 printf("END: %lu = %s",(unsigned long)end_time,ctime(&end_time)); 01454 printf("PREFERRED: %lu = %s",(unsigned long)preferred_time,ctime(&preferred_time)); 01455 printf("CURRENT: %lu = %s",(unsigned long)current_time,ctime(¤t_time)); 01456 #endif 01457 01458 /* skip this date range its out of bounds with what we want */ 01459 if(preferred_time > end_time) 01460 continue; 01461 01462 /* how many days at a time should we advance? */ 01463 if(temp_daterange->skip_interval>1) 01464 advance_interval=temp_daterange->skip_interval; 01465 else 01466 advance_interval=1; 01467 01468 /* advance through the date range */ 01469 for(day_start=start_time;day_start<=end_time;day_start+=(advance_interval*3600*24)){ 01470 01471 /* we already found a time from a higher-precendence date range exception */ 01472 if(day_start>=earliest_day && have_earliest_time==TRUE) 01473 continue; 01474 01475 for(temp_timerange=temp_daterange->times;temp_timerange!=NULL;temp_timerange=temp_timerange->next){ 01476 01477 /* ranges with start/end of zero mean exlude this day */ 01478 if(temp_timerange->range_start==0 && temp_timerange->range_end==0) 01479 continue; 01480 01481 day_range_start=(time_t)(day_start + temp_timerange->range_start); 01482 day_range_end=(time_t)(day_start + temp_timerange->range_end); 01483 01484 #ifdef TEST_TIMEPERIODS_B 01485 printf(" RANGE START: %lu (%lu) = %s",temp_timerange->range_start,(unsigned long)day_range_start,ctime(&day_range_start)); 01486 printf(" RANGE END: %lu (%lu) = %s",temp_timerange->range_end,(unsigned long)day_range_end,ctime(&day_range_end)); 01487 #endif 01488 01489 /* range is out of bounds */ 01490 if(day_range_end<preferred_time) 01491 continue; 01492 01493 /* preferred time occurs before range start, so use range start time as earliest potential time */ 01494 if(day_range_start>=preferred_time) 01495 potential_time=day_range_start; 01496 /* preferred time occurs between range start/end, so use preferred time as earliest potential time */ 01497 else if(day_range_end>=preferred_time) 01498 potential_time=preferred_time; 01499 01500 /* is this the earliest time found thus far? */ 01501 if(have_earliest_time==FALSE || potential_time<earliest_time){ 01502 have_earliest_time=TRUE; 01503 earliest_time=potential_time; 01504 earliest_day=day_start; 01505 #ifdef TEST_TIMEPERIODS_B 01506 printf(" EARLIEST TIME: %lu = %s",(unsigned long)earliest_time,ctime(&earliest_time)); 01507 #endif 01508 } 01509 } 01510 } 01511 } 01512 01513 } 01514 01515 01516 /**** find next available time from normal, weekly rotating schedule (in this timeperiod definition) ****/ 01517 01518 /* check a one week rotation of time */ 01519 has_looped=FALSE; 01520 for(weekday=pref_time_wday,days_into_the_future=0;;weekday++,days_into_the_future++){ 01521 01522 /* break out of the loop if we have checked an entire week already */ 01523 if(has_looped==TRUE && weekday >= pref_time_wday) 01524 break; 01525 01526 if(weekday>=7){ 01527 weekday-=7; 01528 has_looped=TRUE; 01529 } 01530 01531 /* calculate start of this future weekday */ 01532 day_start=(time_t)(midnight + (days_into_the_future*3600*24)); 01533 01534 /* we already found a time from a higher-precendence date range exception */ 01535 if(day_start==earliest_day) 01536 continue; 01537 01538 /* check all time ranges for this day of the week */ 01539 for(temp_timerange=tperiod->days[weekday];temp_timerange!=NULL;temp_timerange=temp_timerange->next){ 01540 01541 /* calculate the time for the start of this time range */ 01542 day_range_start=(time_t)(day_start + temp_timerange->range_start); 01543 01544 if((have_earliest_time==FALSE || day_range_start<earliest_time) && day_range_start>=preferred_time){ 01545 have_earliest_time=TRUE; 01546 earliest_time=day_range_start; 01547 earliest_day=day_start; 01548 } 01549 } 01550 } 01551 01552 01553 /* if we couldn't find a time period there must be none defined */ 01554 if(have_earliest_time==FALSE || earliest_time==(time_t)0) 01555 *valid_time=(time_t)preferred_time; 01556 01557 /* else use the calculated time */ 01558 else 01559 *valid_time=earliest_time; 01560 01561 return; 01562 } 01563 01564 void get_min_invalid_time_per_timeperiod(time_t pref_time, time_t *valid_time, time_t current_time, timeperiod *tperiod){ 01565 time_t preferred_time=(time_t)0L; 01566 timerange *temp_timerange; 01567 daterange *temp_daterange; 01568 time_t midnight=0L; 01569 struct tm *t, tm_s; 01570 time_t day_start=(time_t)0L; 01571 time_t day_range_start=(time_t)0L; 01572 time_t day_range_end=(time_t)0L; 01573 time_t start_time=(time_t)0L; 01574 time_t end_time=(time_t)0L; 01575 int have_latest_time=FALSE; 01576 time_t latest_time=(time_t)0L; 01577 time_t earliest_day=(time_t)0L; 01578 time_t potential_time=(time_t)0L; 01579 int weekday=0; 01580 int has_looped=FALSE; 01581 int days_into_the_future=0; 01582 int daterange_type=0; 01583 unsigned long days=0L; 01584 unsigned long advance_interval=0L; 01585 int year=0; /* new */ 01586 int month=0; /* new */ 01587 01588 int pref_time_year=0; 01589 int pref_time_mon=0; 01590 int pref_time_mday=0; 01591 int pref_time_wday=0; 01592 int current_time_year=0; 01593 int current_time_mon=0; 01594 int current_time_mday=0; 01595 int current_time_wday=0; 01596 int shift; 01597 01598 log_debug_info(DEBUGL_FUNCTIONS,0,"get_next_valid_time_per_timeperiod()\n"); 01599 01600 preferred_time=pref_time; 01601 01602 /* if no timeperiod, go with preferred time */ 01603 if(tperiod==NULL){ 01604 *valid_time=preferred_time; 01605 return; 01606 } 01607 01608 /* calculate the start of the day (midnight, 00:00 hours) of preferred time */ 01609 t = localtime_r(&preferred_time, &tm_s); 01610 t->tm_sec=0; 01611 t->tm_min=0; 01612 t->tm_hour=0; 01613 t->tm_isdst=-1; 01614 midnight=(unsigned long)mktime(t); 01615 01616 /* save pref time values for later */ 01617 pref_time_year=t->tm_year; 01618 pref_time_mon=t->tm_mon; 01619 pref_time_mday=t->tm_mday; 01620 pref_time_wday=t->tm_wday; 01621 01622 /* save current time values for later */ 01623 t = localtime_r(¤t_time, &tm_s); 01624 current_time_year=t->tm_year; 01625 current_time_mon=t->tm_mon; 01626 current_time_mday=t->tm_mday; 01627 current_time_wday=t->tm_wday; 01628 01629 /**** check exceptions (in this timeperiod definition) first ****/ 01630 for(daterange_type=0;daterange_type<DATERANGE_TYPES;daterange_type++){ 01631 01632 for(temp_daterange=tperiod->exceptions[daterange_type];temp_daterange!=NULL;temp_daterange=temp_daterange->next){ 01633 01634 /* get the start time */ 01635 switch(daterange_type){ 01636 case DATERANGE_CALENDAR_DATE: /* 2009-08-11 */ 01637 t->tm_sec=0; 01638 t->tm_min=0; 01639 t->tm_hour=0; 01640 t->tm_mday=temp_daterange->smday; 01641 t->tm_mon=temp_daterange->smon; 01642 t->tm_year=(temp_daterange->syear-1900); 01643 t->tm_isdst=-1; 01644 start_time=mktime(t); 01645 break; 01646 case DATERANGE_MONTH_DATE: /* january 1 */ 01647 /* what year should we use? */ 01648 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01649 /* advance an additional year if we already passed the end month date */ 01650 if((temp_daterange->emon < current_time_mon) || ((temp_daterange->emon == current_time_mon) && temp_daterange->emday < current_time_mday)) 01651 year++; 01652 start_time=calculate_time_from_day_of_month(year,temp_daterange->smon,temp_daterange->smday); 01653 break; 01654 case DATERANGE_MONTH_DAY: /* day 3 */ 01655 /* what year should we use? */ 01656 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01657 /* use current month */ 01658 month=current_time_mon; 01659 /* advance an additional month (and possibly the year) if we already passed the end day of month */ 01660 if(temp_daterange->emday < current_time_mday){ 01661 /*if(month==1){*/ 01662 if(month==11){ 01663 month=0; 01664 year++; 01665 } 01666 else 01667 month++; 01668 } 01669 start_time=calculate_time_from_day_of_month(year,month,temp_daterange->smday); 01670 break; 01671 case DATERANGE_MONTH_WEEK_DAY: /* thursday 2 april */ 01672 /* what year should we use? */ 01673 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01674 /* calculate time of specified weekday of specific month */ 01675 start_time=calculate_time_from_weekday_of_month(year,temp_daterange->smon,temp_daterange->swday,temp_daterange->swday_offset); 01676 /* advance to next year if we've passed this month weekday already this year */ 01677 if(start_time < preferred_time){ 01678 year++; 01679 start_time=calculate_time_from_weekday_of_month(year,temp_daterange->smon,temp_daterange->swday,temp_daterange->swday_offset); 01680 } 01681 break; 01682 case DATERANGE_WEEK_DAY: /* wednesday 1 */ 01683 /* what year should we use? */ 01684 year=(pref_time_year < current_time_year)?current_time_year:pref_time_year; 01685 /* calculate time of specified weekday of month */ 01686 start_time=calculate_time_from_weekday_of_month(year,pref_time_mon,temp_daterange->swday,temp_daterange->swday_offset); 01687 /* advance to next month (or year) if we've passed this weekday of this month already */ 01688 if(start_time < preferred_time){ 01689 month=pref_time_mon; 01690 if(month==11){ 01691 month=0; 01692 year++; 01693 } 01694 else 01695 month++; 01696 start_time=calculate_time_from_weekday_of_month(year,month,temp_daterange->swday,temp_daterange->swday_offset); 01697 } 01698 break; 01699 default: 01700 continue; 01701 break; 01702 } 01703 01704 /* get the end time */ 01705 switch(daterange_type){ 01706 case DATERANGE_CALENDAR_DATE: 01707 t->tm_sec=0; 01708 t->tm_min=0; 01709 t->tm_hour=0; 01710 t->tm_mday=temp_daterange->emday; 01711 t->tm_mon=temp_daterange->emon; 01712 t->tm_year=(temp_daterange->eyear-1900); 01713 t->tm_isdst=-1; 01714 end_time=mktime(t); 01715 break; 01716 case DATERANGE_MONTH_DATE: 01717 /* use same year as was calculated for start time above */ 01718 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,temp_daterange->emday); 01719 /* advance a year if necessary: august 5 - february 2 */ 01720 if(end_time<start_time){ 01721 year++; 01722 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,temp_daterange->emday); 01723 } 01724 break; 01725 case DATERANGE_MONTH_DAY: 01726 /* use same year and month as was calculated for start time above */ 01727 end_time=calculate_time_from_day_of_month(year,month,temp_daterange->emday+1); 01728 break; 01729 case DATERANGE_MONTH_WEEK_DAY: 01730 /* use same year as was calculated for start time above */ 01731 end_time=calculate_time_from_weekday_of_month(year,temp_daterange->emon,temp_daterange->ewday,temp_daterange->ewday_offset); 01732 /* advance a year if necessary: thursday 2 august - monday 3 february */ 01733 if(end_time<start_time){ 01734 year++; 01735 end_time=calculate_time_from_weekday_of_month(year,temp_daterange->emon,temp_daterange->ewday,temp_daterange->ewday_offset); 01736 } 01737 break; 01738 case DATERANGE_WEEK_DAY: 01739 /* use same year and month as was calculated for start time above */ 01740 end_time=calculate_time_from_weekday_of_month(year,month,temp_daterange->ewday,temp_daterange->ewday_offset); 01741 break; 01742 default: 01743 continue; 01744 break; 01745 } 01746 01747 /* start date was bad, so skip this date range */ 01748 if((unsigned long)start_time==0L) 01749 continue; 01750 01751 /* end date was bad - see if we can handle the error */ 01752 if((unsigned long)end_time==0L){ 01753 switch(daterange_type){ 01754 case DATERANGE_CALENDAR_DATE: 01755 continue; 01756 break; 01757 case DATERANGE_MONTH_DATE: 01758 /* end date can't be helped, so skip it */ 01759 if(temp_daterange->emday<0) 01760 continue; 01761 01762 /* else end date slipped past end of month, so use last day of month as end date */ 01763 end_time=calculate_time_from_day_of_month(year,temp_daterange->emon,-1); 01764 break; 01765 case DATERANGE_MONTH_DAY: 01766 /* end date can't be helped, so skip it */ 01767 if(temp_daterange->emday<0) 01768 continue; 01769 01770 /* else end date slipped past end of month, so use last day of month as end date */ 01771 end_time=calculate_time_from_day_of_month(year,month,-1); 01772 break; 01773 case DATERANGE_MONTH_WEEK_DAY: 01774 /* end date can't be helped, so skip it */ 01775 if(temp_daterange->ewday_offset<0) 01776 continue; 01777 01778 /* else end date slipped past end of month, so use last day of month as end date */ 01779 end_time=calculate_time_from_day_of_month(year,pref_time_mon,-1); 01780 break; 01781 case DATERANGE_WEEK_DAY: 01782 /* end date can't be helped, so skip it */ 01783 if(temp_daterange->ewday_offset<0) 01784 continue; 01785 01786 /* else end date slipped past end of month, so use last day of month as end date */ 01787 end_time=calculate_time_from_day_of_month(year,month,-1); 01788 break; 01789 default: 01790 continue; 01791 break; 01792 } 01793 } 01794 01795 01796 /* if skipping days... */ 01797 if(temp_daterange->skip_interval>1){ 01798 01799 /* advance to the next possible skip date */ 01800 if(start_time<preferred_time){ 01801 /* check if interval is across dlst change and gets the compensation */ 01802 shift=get_dlst_shift(&start_time,&midnight); 01803 01804 /* how many days have passed between skip start date and preferred time? */ 01805 days=(shift+midnight-(unsigned long)start_time)/(3600*24); 01806 01807 /* advance start date to next skip day */ 01808 if((days % temp_daterange->skip_interval)==0) 01809 start_time+=(days*3600*24); 01810 else 01811 start_time+=((days-(days % temp_daterange->skip_interval)+temp_daterange->skip_interval)*3600*24); 01812 } 01813 01814 /* if skipping has no end, use start date as end */ 01815 if((daterange_type==DATERANGE_CALENDAR_DATE) && is_daterange_single_day(temp_daterange)==TRUE) 01816 end_time=start_time; 01817 } 01818 01819 /* skip this date range its out of bounds with what we want */ 01820 if(preferred_time > end_time) 01821 continue; 01822 01823 /* how many days at a time should we advance? */ 01824 if(temp_daterange->skip_interval>1) 01825 advance_interval=temp_daterange->skip_interval; 01826 else 01827 advance_interval=1; 01828 01829 /* advance through the date range */ 01830 for(day_start=start_time;day_start<=end_time;day_start+=(advance_interval*3600*24)){ 01831 01832 /* we already found a time from a higher-precendence date range exception */ 01833 if(day_start>=earliest_day && have_latest_time==TRUE) 01834 continue; 01835 01836 for(temp_timerange=temp_daterange->times;temp_timerange!=NULL;temp_timerange=temp_timerange->next){ 01837 01838 day_range_start=(time_t)(day_start + temp_timerange->range_start); 01839 day_range_end=(time_t)(day_start + temp_timerange->range_end); 01840 01841 /* range is out of bounds */ 01842 if(day_range_end<preferred_time) 01843 continue; 01844 01845 potential_time=day_range_end; 01846 01847 /* is this the earliest time found thus far? */ 01848 if(have_latest_time==FALSE || potential_time<latest_time){ 01849 have_latest_time=TRUE; 01850 latest_time=potential_time; 01851 earliest_day=day_start; 01852 } 01853 } 01854 } 01855 } 01856 01857 } 01858 01859 01860 /**** find next available time from normal, weekly rotating schedule (in this timeperiod definition) ****/ 01861 01862 /* check a one week rotation of time */ 01863 has_looped=FALSE; 01864 for(weekday=pref_time_wday,days_into_the_future=0;;weekday++,days_into_the_future++){ 01865 01866 /* break out of the loop if we have checked an entire week already */ 01867 if(has_looped==TRUE && weekday >= pref_time_wday) 01868 break; 01869 01870 if(weekday>=7){ 01871 weekday-=7; 01872 has_looped=TRUE; 01873 } 01874 01875 /* calculate start of this future weekday */ 01876 day_start=(time_t)(midnight + (days_into_the_future*3600*24)); 01877 01878 /* we already found a time from a higher-precendence date range exception */ 01879 if(day_start==earliest_day) 01880 continue; 01881 01882 /* check all time ranges for this day of the week */ 01883 for(temp_timerange=tperiod->days[weekday];temp_timerange!=NULL;temp_timerange=temp_timerange->next){ 01884 01885 /* calculate the time for the start of this time range */ 01886 day_range_start=(time_t)(day_start + temp_timerange->range_start); 01887 day_range_end=(time_t)(day_start + temp_timerange->range_end); 01888 01889 if((have_latest_time==FALSE || day_range_end<latest_time) && day_range_end>=preferred_time){ 01890 have_latest_time=TRUE; 01891 latest_time=day_range_end; 01892 earliest_day=day_start; 01893 } 01894 } 01895 } 01896 01897 01898 /* if we couldn't find a time period there must be none defined */ 01899 if(have_latest_time==FALSE || latest_time==(time_t)0) 01900 *valid_time=(time_t)preferred_time; 01901 01902 /* else use the calculated time */ 01903 else 01904 *valid_time=latest_time; 01905 01906 return; 01907 } 01908 01909 01910 01911 /* given a preferred time, get the next valid time within a time period */ 01912 void get_next_valid_time(time_t pref_time, time_t *valid_time, timeperiod *tperiod){ 01913 time_t current_time=(time_t)0L; 01914 01915 log_debug_info(DEBUGL_FUNCTIONS,0,"get_next_valid_time()\n"); 01916 01917 /* get time right now, preferred time must be now or in the future */ 01918 time(¤t_time); 01919 01920 _get_next_valid_time(pref_time, current_time, valid_time, tperiod); 01921 } 01922 01923 01924 01925 /* tests if a date range covers just a single day */ 01926 int is_daterange_single_day(daterange *dr){ 01927 01928 if(dr==NULL) 01929 return FALSE; 01930 01931 if(dr->syear!=dr->eyear) 01932 return FALSE; 01933 if(dr->smon!=dr->emon) 01934 return FALSE; 01935 if(dr->smday!=dr->emday) 01936 return FALSE; 01937 if(dr->swday!=dr->ewday) 01938 return FALSE; 01939 if(dr->swday_offset!=dr->ewday_offset) 01940 return FALSE; 01941 01942 return TRUE; 01943 } 01944 01945 01946 01947 /* returns a time (midnight) of particular (3rd, last) day in a given month */ 01948 time_t calculate_time_from_day_of_month(int year, int month, int monthday){ 01949 time_t midnight; 01950 int day=0; 01951 struct tm t; 01952 01953 #ifdef TEST_TIMEPERIODS 01954 printf("YEAR: %d, MON: %d, MDAY: %d\n",year,month,monthday); 01955 #endif 01956 01957 /* positive day (3rd day) */ 01958 if(monthday>0){ 01959 01960 t.tm_sec=0; 01961 t.tm_min=0; 01962 t.tm_hour=0; 01963 t.tm_year=year; 01964 t.tm_mon=month; 01965 t.tm_mday=monthday; 01966 t.tm_isdst=-1; 01967 01968 midnight=mktime(&t); 01969 01970 #ifdef TEST_TIMEPERIODS 01971 printf("MIDNIGHT CALC: %s",ctime(&midnight)); 01972 #endif 01973 01974 /* if we rolled over to the next month, time is invalid */ 01975 /* assume the user's intention is to keep it in the current month */ 01976 if(t.tm_mon!=month) 01977 midnight=(time_t)0L; 01978 } 01979 01980 /* negative offset (last day, 3rd to last day) */ 01981 else{ 01982 /* find last day in the month */ 01983 day=32; 01984 do{ 01985 /* back up a day */ 01986 day--; 01987 01988 /* make the new time */ 01989 t.tm_mon=month; 01990 t.tm_year=year; 01991 t.tm_mday=day; 01992 t.tm_isdst=-1; 01993 midnight=mktime(&t); 01994 01995 }while(t.tm_mon!=month); 01996 01997 /* now that we know the last day, back up more */ 01998 /* make the new time */ 01999 t.tm_mon=month; 02000 t.tm_year=year; 02001 /* -1 means last day of month, so add one to to make this correct - Mike Bird */ 02002 t.tm_mday+=(monthday<-30)?-30:monthday+1; 02003 t.tm_isdst=-1; 02004 midnight=mktime(&t); 02005 02006 /* if we rolled over to the previous month, time is invalid */ 02007 /* assume the user's intention is to keep it in the current month */ 02008 if(t.tm_mon!=month) 02009 midnight=(time_t)0L; 02010 } 02011 02012 return midnight; 02013 } 02014 02015 02016 02017 /* returns a time (midnight) of particular (3rd, last) weekday in a given month */ 02018 time_t calculate_time_from_weekday_of_month(int year, int month, int weekday, int weekday_offset){ 02019 time_t midnight; 02020 int days=0; 02021 int weeks=0; 02022 struct tm t; 02023 02024 t.tm_sec=0; 02025 t.tm_min=0; 02026 t.tm_hour=0; 02027 t.tm_year=year; 02028 t.tm_mon=month; 02029 t.tm_mday=1; 02030 t.tm_isdst=-1; 02031 02032 midnight=mktime(&t); 02033 02034 /* how many days must we advance to reach the first instance of the weekday this month? */ 02035 days=weekday-(t.tm_wday); 02036 if(days<0) 02037 days+=7; 02038 02039 /* positive offset (3rd thursday) */ 02040 if(weekday_offset>0){ 02041 02042 /* how many weeks must we advance (no more than 5 possible) */ 02043 weeks=(weekday_offset>5)?5:weekday_offset; 02044 days+=((weeks-1)*7); 02045 02046 /* make the new time */ 02047 t.tm_mon=month; 02048 t.tm_year=year; 02049 t.tm_mday=days+1; 02050 t.tm_isdst=-1; 02051 midnight=mktime(&t); 02052 02053 /* if we rolled over to the next month, time is invalid */ 02054 /* assume the user's intention is to keep it in the current month */ 02055 if(t.tm_mon!=month) 02056 midnight=(time_t)0L; 02057 } 02058 02059 /* negative offset (last thursday, 3rd to last tuesday) */ 02060 else{ 02061 /* find last instance of weekday in the month */ 02062 days+=(5*7); 02063 do{ 02064 /* back up a week */ 02065 days-=7; 02066 02067 /* make the new time */ 02068 t.tm_mon=month; 02069 t.tm_year=year; 02070 t.tm_mday=days+1; 02071 t.tm_isdst=-1; 02072 midnight=mktime(&t); 02073 02074 }while(t.tm_mon!=month); 02075 02076 /* now that we know the last instance of the weekday, back up more */ 02077 weeks=(weekday_offset<-5)?-5:weekday_offset; 02078 days=((weeks+1)*7); 02079 02080 /* make the new time */ 02081 t.tm_mon=month; 02082 t.tm_year=year; 02083 t.tm_mday+=days; 02084 t.tm_isdst=-1; 02085 midnight=mktime(&t); 02086 02087 /* if we rolled over to the previous month, time is invalid */ 02088 /* assume the user's intention is to keep it in the current month */ 02089 if(t.tm_mon!=month) 02090 midnight=(time_t)0L; 02091 } 02092 02093 return midnight; 02094 } 02095 02096 02097 /* get the next time to schedule a log rotation */ 02098 time_t get_next_log_rotation_time(void){ 02099 time_t current_time; 02100 struct tm *t, tm_s; 02101 int is_dst_now=FALSE; 02102 time_t run_time; 02103 02104 time(¤t_time); 02105 t = localtime_r(¤t_time, &tm_s); 02106 t->tm_min=0; 02107 t->tm_sec=0; 02108 is_dst_now=(t->tm_isdst>0)?TRUE:FALSE; 02109 02110 switch(log_rotation_method){ 02111 case LOG_ROTATION_HOURLY: 02112 t->tm_hour++; 02113 run_time=mktime(t); 02114 break; 02115 case LOG_ROTATION_DAILY: 02116 t->tm_mday++; 02117 t->tm_hour=0; 02118 run_time=mktime(t); 02119 break; 02120 case LOG_ROTATION_WEEKLY: 02121 t->tm_mday+=(7-t->tm_wday); 02122 t->tm_hour=0; 02123 run_time=mktime(t); 02124 break; 02125 case LOG_ROTATION_MONTHLY: 02126 default: 02127 t->tm_mon++; 02128 t->tm_mday=1; 02129 t->tm_hour=0; 02130 run_time=mktime(t); 02131 break; 02132 } 02133 02134 if(is_dst_now==TRUE && t->tm_isdst==0) 02135 run_time+=3600; 02136 else if(is_dst_now==FALSE && t->tm_isdst>0) 02137 run_time-=3600; 02138 02139 return run_time; 02140 } 02141 02142 02143 02144 /******************************************************************/ 02145 /******************** SIGNAL HANDLER FUNCTIONS ********************/ 02146 /******************************************************************/ 02147 02148 02149 /* trap signals so we can exit gracefully */ 02150 void setup_sighandler(void){ 02151 02152 /* reset the shutdown flag */ 02153 sigshutdown=FALSE; 02154 02155 /* remove buffering from stderr, stdin, and stdout */ 02156 setbuf(stdin,(char *)NULL); 02157 setbuf(stdout,(char *)NULL); 02158 setbuf(stderr,(char *)NULL); 02159 02160 /* initialize signal handling */ 02161 signal(SIGPIPE,SIG_IGN); 02162 signal(SIGQUIT,sighandler); 02163 signal(SIGTERM,sighandler); 02164 signal(SIGHUP,sighandler); 02165 if(daemon_dumps_core==FALSE && daemon_mode==TRUE) 02166 signal(SIGSEGV,sighandler); 02167 02168 return; 02169 } 02170 02171 02172 /* reset signal handling... */ 02173 void reset_sighandler(void){ 02174 02175 /* set signal handling to default actions */ 02176 signal(SIGQUIT,SIG_DFL); 02177 signal(SIGTERM,SIG_DFL); 02178 signal(SIGHUP,SIG_DFL); 02179 signal(SIGSEGV,SIG_DFL); 02180 signal(SIGPIPE,SIG_DFL); 02181 02182 return; 02183 } 02184 02185 02186 /* handle signals */ 02187 void sighandler(int sig){ 02188 int x=0; 02189 02190 /* if shutdown is already true, we're in a signal trap loop! */ 02191 /* changed 09/07/06 to only exit on segfaults */ 02192 if(sigshutdown==TRUE && sig==SIGSEGV) 02193 exit(ERROR); 02194 02195 caught_signal=TRUE; 02196 02197 if(sig<0) 02198 sig=-sig; 02199 02200 for(x=0;sigs[x]!=(char *)NULL;x++); 02201 sig%=x; 02202 02203 sig_id=sig; 02204 02205 /* log errors about segfaults now, as we might not get a chance to later */ 02206 /* all other signals are logged at a later point in main() to prevent problems with NPTL */ 02207 if(sig==SIGSEGV) 02208 logit(NSLOG_PROCESS_INFO,TRUE,"Caught SIG%s, shutting down...\n",sigs[sig]); 02209 02210 /* we received a SIGHUP, so restart... */ 02211 if(sig==SIGHUP) 02212 sigrestart=TRUE; 02213 02214 /* else begin shutting down... */ 02215 else if(sig<16) 02216 sigshutdown=TRUE; 02217 02218 return; 02219 } 02220 02221 02222 /* handle timeouts when executing service checks */ 02223 /* 07/16/08 EG also called when parent process gets a TERM signal */ 02224 void service_check_sighandler(int sig){ 02225 struct timeval end_time; 02226 02227 /* get the current time */ 02228 gettimeofday(&end_time,NULL); 02229 02230 check_result_info.return_code=service_check_timeout_state; 02231 check_result_info.finish_time=end_time; 02232 check_result_info.early_timeout=TRUE; 02233 02234 /* write check result to file */ 02235 if(check_result_info.output_file_fp){ 02236 02237 fprintf(check_result_info.output_file_fp,"finish_time=%lu.%lu\n",check_result_info.finish_time.tv_sec,check_result_info.finish_time.tv_usec); 02238 fprintf(check_result_info.output_file_fp,"early_timeout=%d\n",check_result_info.early_timeout); 02239 fprintf(check_result_info.output_file_fp,"exited_ok=%d\n",check_result_info.exited_ok); 02240 fprintf(check_result_info.output_file_fp,"return_code=%d\n",check_result_info.return_code); 02241 fprintf(check_result_info.output_file_fp,"output=%s\n","(Service Check Timed Out)"); 02242 02243 /* close the temp file */ 02244 fclose(check_result_info.output_file_fp); 02245 02246 /* move check result to queue directory */ 02247 move_check_result_to_queue(check_result_info.output_file); 02248 } 02249 02250 /* free check result memory */ 02251 free_check_result(&check_result_info); 02252 02253 /* try to kill the command that timed out by sending termination signal to our process group */ 02254 /* we also kill ourselves while doing this... */ 02255 kill((pid_t)0,SIGKILL); 02256 02257 /* force the child process (service check) to exit... */ 02258 _exit(STATE_CRITICAL); 02259 } 02260 02261 02262 /* handle timeouts when executing host checks */ 02263 /* 07/16/08 EG also called when parent process gets a TERM signal */ 02264 void host_check_sighandler(int sig){ 02265 struct timeval end_time; 02266 02267 /* get the current time */ 02268 gettimeofday(&end_time,NULL); 02269 02270 check_result_info.return_code=STATE_CRITICAL; 02271 check_result_info.finish_time=end_time; 02272 check_result_info.early_timeout=TRUE; 02273 02274 /* write check result to file */ 02275 if(check_result_info.output_file_fp){ 02276 02277 fprintf(check_result_info.output_file_fp,"finish_time=%lu.%lu\n",check_result_info.finish_time.tv_sec,check_result_info.finish_time.tv_usec); 02278 fprintf(check_result_info.output_file_fp,"early_timeout=%d\n",check_result_info.early_timeout); 02279 fprintf(check_result_info.output_file_fp,"exited_ok=%d\n",check_result_info.exited_ok); 02280 fprintf(check_result_info.output_file_fp,"return_code=%d\n",check_result_info.return_code); 02281 fprintf(check_result_info.output_file_fp,"output=%s\n","(Host Check Timed Out)"); 02282 02283 /* close the temp file */ 02284 fclose(check_result_info.output_file_fp); 02285 02286 /* move check result to queue directory */ 02287 move_check_result_to_queue(check_result_info.output_file); 02288 } 02289 02290 /* free check result memory */ 02291 free_check_result(&check_result_info); 02292 02293 /* try to kill the command that timed out by sending termination signal to our process group */ 02294 /* we also kill ourselves while doing this... */ 02295 kill((pid_t)0,SIGKILL); 02296 02297 /* force the child process (service check) to exit... */ 02298 _exit(STATE_CRITICAL); 02299 } 02300 02301 02302 /* handle timeouts when executing commands via my_system_r() */ 02303 void my_system_sighandler(int sig){ 02304 02305 /* force the child process to exit... */ 02306 _exit(STATE_CRITICAL); 02307 } 02308 02309 02310 02311 02312 /******************************************************************/ 02313 /************************ DAEMON FUNCTIONS ************************/ 02314 /******************************************************************/ 02315 02316 int daemon_init(void){ 02317 pid_t pid=-1; 02318 int pidno=0; 02319 int lockfile=0; 02320 int val=0; 02321 char buf[256]; 02322 struct flock lock; 02323 char *homedir=NULL; 02324 02325 #ifdef RLIMIT_CORE 02326 struct rlimit limit; 02327 #endif 02328 02329 /* change working directory. scuttle home if we're dumping core */ 02330 homedir=getenv("HOME"); 02331 if(daemon_dumps_core==TRUE && homedir!=NULL) 02332 dummy=chdir(homedir); 02333 else 02334 dummy=chdir("/"); 02335 02336 umask(S_IWGRP|S_IWOTH); 02337 02338 lockfile=open(lock_file,O_RDWR | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 02339 02340 if(lockfile<0){ 02341 logit(NSLOG_RUNTIME_ERROR,TRUE,"Failed to obtain lock on file %s: %s\n", lock_file, strerror(errno)); 02342 logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR,TRUE,"Bailing out due to errors encountered while attempting to daemonize... (PID=%d)",(int)getpid()); 02343 02344 cleanup(); 02345 exit(ERROR); 02346 } 02347 02348 /* see if we can read the contents of the lockfile */ 02349 if((val=read(lockfile,buf,(size_t)10))<0){ 02350 logit(NSLOG_RUNTIME_ERROR,TRUE,"Lockfile exists but cannot be read"); 02351 cleanup(); 02352 exit(ERROR); 02353 } 02354 02355 /* we read something - check the PID */ 02356 if(val>0){ 02357 if((val=sscanf(buf,"%d",&pidno))<1){ 02358 logit(NSLOG_RUNTIME_ERROR,TRUE,"Lockfile '%s' does not contain a valid PID (%s)",lock_file,buf); 02359 cleanup(); 02360 exit(ERROR); 02361 } 02362 } 02363 02364 /* check for SIGHUP */ 02365 if(val==1 && (pid=(pid_t)pidno)==getpid()){ 02366 close(lockfile); 02367 return OK; 02368 } 02369 02370 /* exit on errors... */ 02371 if((pid=fork())<0) 02372 return(ERROR); 02373 02374 /* parent process goes away.. */ 02375 else if((int)pid!=0) 02376 exit(OK); 02377 02378 /* child continues... */ 02379 02380 /* child becomes session leader... */ 02381 setsid(); 02382 02383 /* place a file lock on the lock file */ 02384 lock.l_type=F_WRLCK; 02385 lock.l_start=0; 02386 lock.l_whence=SEEK_SET; 02387 lock.l_len=0; 02388 if(fcntl(lockfile,F_SETLK,&lock)<0){ 02389 if(errno==EACCES || errno==EAGAIN){ 02390 fcntl(lockfile,F_GETLK,&lock); 02391 logit(NSLOG_RUNTIME_ERROR,TRUE,"Lockfile '%s' looks like its already held by another instance of %s (PID %d). Bailing out...", PROGRAM_NAME, lock_file, (int)lock.l_pid); 02392 } 02393 else 02394 logit(NSLOG_RUNTIME_ERROR,TRUE,"Cannot lock lockfile '%s': %s. Bailing out...",lock_file,strerror(errno)); 02395 02396 cleanup(); 02397 exit(ERROR); 02398 } 02399 02400 /* prevent daemon from dumping a core file... */ 02401 #ifdef RLIMIT_CORE 02402 if(daemon_dumps_core==FALSE){ 02403 getrlimit(RLIMIT_CORE,&limit); 02404 limit.rlim_cur=0; 02405 setrlimit(RLIMIT_CORE,&limit); 02406 } 02407 #endif 02408 02409 /* write PID to lockfile... */ 02410 lseek(lockfile,0,SEEK_SET); 02411 dummy=ftruncate(lockfile,0); 02412 sprintf(buf,"%d\n",(int)getpid()); 02413 dummy=write(lockfile,buf,strlen(buf)); 02414 02415 /* make sure lock file stays open while program is executing... */ 02416 val=fcntl(lockfile,F_GETFD,0); 02417 val|=FD_CLOEXEC; 02418 fcntl(lockfile,F_SETFD,val); 02419 02420 /* close existing stdin, stdout, stderr */ 02421 close(0); 02422 close(1); 02423 close(2); 02424 02425 /* THIS HAS TO BE DONE TO AVOID PROBLEMS WITH STDERR BEING REDIRECTED TO SERVICE MESSAGE PIPE! */ 02426 /* re-open stdin, stdout, stderr with known values */ 02427 open("/dev/null",O_RDONLY); 02428 open("/dev/null",O_WRONLY); 02429 open("/dev/null",O_WRONLY); 02430 02431 #ifdef USE_EVENT_BROKER 02432 /* send program data to broker */ 02433 broker_program_state(NEBTYPE_PROCESS_DAEMONIZE,NEBFLAG_NONE,NEBATTR_NONE,NULL); 02434 #endif 02435 02436 return OK; 02437 } 02438 02439 02440 02441 /******************************************************************/ 02442 /*********************** SECURITY FUNCTIONS ***********************/ 02443 /******************************************************************/ 02444 02445 /* drops privileges */ 02446 int drop_privileges(char *user, char *group){ 02447 uid_t uid=-1; 02448 gid_t gid=-1; 02449 struct group *grp=NULL; 02450 struct passwd *pw=NULL; 02451 int result=OK; 02452 02453 log_debug_info(DEBUGL_FUNCTIONS,0,"drop_privileges() start\n"); 02454 log_debug_info(DEBUGL_PROCESS,0,"Original UID/GID: %d/%d\n",(int)getuid(),(int)getgid()); 02455 02456 /* only drop privileges if we're running as root, so we don't interfere with being debugged while running as some random user */ 02457 if(getuid()!=0) 02458 return OK; 02459 02460 /* set effective group ID */ 02461 if(group!=NULL){ 02462 02463 /* see if this is a group name */ 02464 if(strspn(group,"0123456789")<strlen(group)){ 02465 grp=(struct group *)getgrnam(group); 02466 if(grp!=NULL) 02467 gid=(gid_t)(grp->gr_gid); 02468 else 02469 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Could not get group entry for '%s'",group); 02470 } 02471 02472 /* else we were passed the GID */ 02473 else 02474 gid=(gid_t)atoi(group); 02475 02476 /* set effective group ID if other than current EGID */ 02477 if(gid!=getegid()){ 02478 02479 if(setgid(gid)==-1){ 02480 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Could not set effective GID=%d",(int)gid); 02481 result=ERROR; 02482 } 02483 } 02484 } 02485 02486 02487 /* set effective user ID */ 02488 if(user!=NULL){ 02489 02490 /* see if this is a user name */ 02491 if(strspn(user,"0123456789")<strlen(user)){ 02492 pw=(struct passwd *)getpwnam(user); 02493 if(pw!=NULL) 02494 uid=(uid_t)(pw->pw_uid); 02495 else 02496 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Could not get passwd entry for '%s'",user); 02497 } 02498 02499 /* else we were passed the UID */ 02500 else 02501 uid=(uid_t)atoi(user); 02502 02503 #ifdef HAVE_INITGROUPS 02504 02505 if(uid!=geteuid()){ 02506 02507 /* initialize supplementary groups */ 02508 if(initgroups(user,gid)==-1){ 02509 if(errno==EPERM) 02510 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Unable to change supplementary groups using initgroups() -- I hope you know what you're doing"); 02511 else{ 02512 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Possibly root user failed dropping privileges with initgroups()"); 02513 return ERROR; 02514 } 02515 } 02516 } 02517 #endif 02518 if(setuid(uid)==-1){ 02519 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Could not set effective UID=%d",(int)uid); 02520 result=ERROR; 02521 } 02522 } 02523 02524 log_debug_info(DEBUGL_PROCESS,0,"New UID/GID: %d/%d\n",(int)getuid(),(int)getgid()); 02525 02526 return result; 02527 } 02528 02529 02530 02531 02532 /******************************************************************/ 02533 /************************* IPC FUNCTIONS **************************/ 02534 /******************************************************************/ 02535 02536 /* move check result to queue directory */ 02537 int move_check_result_to_queue(char *checkresult_file){ 02538 char *output_file=NULL; 02539 char *temp_buffer=NULL; 02540 int output_file_fd=-1; 02541 mode_t new_umask=077; 02542 mode_t old_umask; 02543 int result=0; 02544 02545 /* save the file creation mask */ 02546 old_umask=umask(new_umask); 02547 02548 /* create a safe temp file */ 02549 dummy=asprintf(&output_file,"%s/cXXXXXX",check_result_path); 02550 output_file_fd=mkstemp(output_file); 02551 02552 /* file created okay */ 02553 if(output_file_fd>=0){ 02554 02555 log_debug_info(DEBUGL_CHECKS,2,"Moving temp check result file '%s' to queue file '%s'...\n",checkresult_file,output_file); 02556 02557 #ifdef __CYGWIN__ 02558 /* Cygwin cannot rename open files - gives Permission Denied */ 02559 /* close the file */ 02560 close(output_file_fd); 02561 #endif 02562 02563 /* move the original file */ 02564 result=my_rename(checkresult_file,output_file); 02565 02566 #ifndef __CYGWIN__ 02567 /* close the file */ 02568 close(output_file_fd); 02569 #endif 02570 02571 /* create an ok-to-go indicator file */ 02572 dummy=asprintf(&temp_buffer,"%s.ok",output_file); 02573 if((output_file_fd=open(temp_buffer,O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR))>=0) 02574 close(output_file_fd); 02575 my_free(temp_buffer); 02576 02577 /* delete the original file if it couldn't be moved */ 02578 if(result!=0) 02579 unlink(checkresult_file); 02580 } 02581 else 02582 result=-1; 02583 02584 /* reset the file creation mask */ 02585 umask(old_umask); 02586 02587 /* log a warning on errors */ 02588 if(result!=0) 02589 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Unable to move file '%s' to check results queue.\n",checkresult_file); 02590 02591 /* free memory */ 02592 my_free(output_file); 02593 02594 return OK; 02595 } 02596 02597 02598 02599 /* processes files in the check result queue directory */ 02600 int process_check_result_queue(char *dirname){ 02601 char file[MAX_FILENAME_LENGTH]; 02602 DIR *dirp=NULL; 02603 struct dirent *dirfile=NULL; 02604 register int x=0; 02605 struct stat stat_buf; 02606 struct stat ok_stat_buf; 02607 char *temp_buffer=NULL; 02608 int result=OK; 02609 02610 /* make sure we have what we need */ 02611 if(dirname==NULL){ 02612 logit(NSLOG_CONFIG_ERROR,TRUE,"Error: No check result queue directory specified.\n"); 02613 return ERROR; 02614 } 02615 02616 /* open the directory for reading */ 02617 if((dirp=opendir(dirname))==NULL){ 02618 logit(NSLOG_CONFIG_ERROR,TRUE,"Error: Could not open check result queue directory '%s' for reading.\n",dirname); 02619 return ERROR; 02620 } 02621 02622 log_debug_info(DEBUGL_CHECKS,1,"Starting to read check result queue '%s'...\n",dirname); 02623 02624 /* process all files in the directory... */ 02625 while((dirfile=readdir(dirp))!=NULL){ 02626 02627 /* create /path/to/file */ 02628 snprintf(file,sizeof(file),"%s/%s",dirname,dirfile->d_name); 02629 file[sizeof(file)-1]='\x0'; 02630 02631 /* process this if it's a check result file... */ 02632 x=strlen(dirfile->d_name); 02633 if(x==7 && dirfile->d_name[0]=='c'){ 02634 02635 if(stat(file,&stat_buf)==-1){ 02636 logit(NSLOG_RUNTIME_WARNING,TRUE,"Warning: Could not stat() check result file '%s'.\n",file); 02637 continue; 02638 } 02639 02640 switch(stat_buf.st_mode & S_IFMT){ 02641 02642 case S_IFREG: 02643 /* don't process symlinked files */ 02644 if(!S_ISREG(stat_buf.st_mode)) 02645 continue; 02646 break; 02647 02648 default: 02649 /* everything else we ignore */ 02650 continue; 02651 break; 02652 } 02653 02654 /* at this point we have a regular file... */ 02655 02656 /* can we find the associated ok-to-go file ? */ 02657 dummy=asprintf(&temp_buffer,"%s.ok",file); 02658 result=stat(temp_buffer,&ok_stat_buf); 02659 my_free(temp_buffer); 02660 if(result==-1) 02661 continue; 02662 02663 /* process the file */ 02664 result=process_check_result_file(file); 02665 02666 /* break out if we encountered an error */ 02667 if(result==ERROR) 02668 break; 02669 } 02670 } 02671 02672 closedir(dirp); 02673 02674 return result; 02675 02676 } 02677 02678 02679 02680 02681 /* reads check result(s) from a file */ 02682 int process_check_result_file(char *fname){ 02683 mmapfile *thefile=NULL; 02684 char *input=NULL; 02685 char *var=NULL; 02686 char *val=NULL; 02687 char *v1=NULL,*v2=NULL; 02688 int delete_file=FALSE; 02689 time_t current_time; 02690 check_result *new_cr=NULL; 02691 02692 if(fname==NULL) 02693 return ERROR; 02694 02695 time(¤t_time); 02696 02697 log_debug_info(DEBUGL_CHECKS,1,"Processing check result file: '%s'\n",fname); 02698 02699 /* open the file for reading */ 02700 if((thefile=mmap_fopen(fname))==NULL){ 02701 02702 /* try removing the file - zero length files can't be mmap()'ed, so it might exist */ 02703 unlink(fname); 02704 02705 return ERROR; 02706 } 02707 02708 /* read in all lines from the file */ 02709 while(1){ 02710 02711 /* free memory */ 02712 my_free(input); 02713 02714 /* read the next line */ 02715 if((input=mmap_fgets_multiline(thefile))==NULL) 02716 break; 02717 02718 /* skip comments */ 02719 if(input[0]=='#') 02720 continue; 02721 02722 /* empty line indicates end of record */ 02723 else if(input[0]=='\n'){ 02724 02725 /* we have something... */ 02726 if(new_cr){ 02727 02728 /* do we have the minimum amount of data? */ 02729 if(new_cr->host_name!=NULL && new_cr->output!=NULL){ 02730 02731 /* add check result to list in memory */ 02732 add_check_result_to_list(new_cr); 02733 02734 /* reset pointer */ 02735 new_cr=NULL; 02736 } 02737 02738 /* discard partial input */ 02739 else{ 02740 free_check_result(new_cr); 02741 init_check_result(new_cr); 02742 new_cr->output_file=(char *)strdup(fname); 02743 } 02744 } 02745 } 02746 02747 if((var=my_strtok(input,"="))==NULL) 02748 continue; 02749 if((val=my_strtok(NULL,"\n"))==NULL) 02750 continue; 02751 02752 /* found the file time */ 02753 if(!strcmp(var,"file_time")){ 02754 02755 /* file is too old - ignore check results it contains and delete it */ 02756 /* this will only work as intended if file_time comes before check results */ 02757 if(max_check_result_file_age>0 && (current_time-(strtoul(val,NULL,0))>max_check_result_file_age)){ 02758 delete_file=TRUE; 02759 break; 02760 } 02761 } 02762 02763 /* else we have check result data */ 02764 else{ 02765 02766 /* allocate new check result if necessary */ 02767 if(new_cr==NULL){ 02768 02769 if((new_cr=(check_result *)malloc(sizeof(check_result)))==NULL) 02770 continue; 02771 02772 /* init values */ 02773 init_check_result(new_cr); 02774 new_cr->output_file=(char *)strdup(fname); 02775 } 02776 02777 if(!strcmp(var,"host_name")) 02778 new_cr->host_name=(char *)strdup(val); 02779 else if(!strcmp(var,"service_description")){ 02780 new_cr->service_description=(char *)strdup(val); 02781 new_cr->object_check_type=SERVICE_CHECK; 02782 } 02783 else if(!strcmp(var,"check_type")) 02784 new_cr->check_type=atoi(val); 02785 else if(!strcmp(var,"check_options")) 02786 new_cr->check_options=atoi(val); 02787 else if(!strcmp(var,"scheduled_check")) 02788 new_cr->scheduled_check=atoi(val); 02789 else if(!strcmp(var,"reschedule_check")) 02790 new_cr->reschedule_check=atoi(val); 02791 else if(!strcmp(var,"latency")) 02792 new_cr->latency=strtod(val,NULL); 02793 else if(!strcmp(var,"start_time")){ 02794 if((v1=strtok(val,"."))==NULL) 02795 continue; 02796 if((v2=strtok(NULL,"\n"))==NULL) 02797 continue; 02798 new_cr->start_time.tv_sec=strtoul(v1,NULL,0); 02799 new_cr->start_time.tv_usec=strtoul(v2,NULL,0); 02800 } 02801 else if(!strcmp(var,"finish_time")){ 02802 if((v1=strtok(val,"."))==NULL) 02803 continue; 02804 if((v2=strtok(NULL,"\n"))==NULL) 02805 continue; 02806 new_cr->finish_time.tv_sec=strtoul(v1,NULL,0); 02807 new_cr->finish_time.tv_usec=strtoul(v2,NULL,0); 02808 } 02809 else if(!strcmp(var,"early_timeout")) 02810 new_cr->early_timeout=atoi(val); 02811 else if(!strcmp(var,"exited_ok")) 02812 new_cr->exited_ok=atoi(val); 02813 else if(!strcmp(var,"return_code")) 02814 new_cr->return_code=atoi(val); 02815 else if(!strcmp(var,"output")) 02816 new_cr->output=(char *)strdup(val); 02817 } 02818 } 02819 02820 /* we have something */ 02821 if(new_cr){ 02822 02823 /* do we have the minimum amount of data? */ 02824 if(new_cr->host_name!=NULL && new_cr->output!=NULL){ 02825 02826 /* add check result to list in memory */ 02827 add_check_result_to_list(new_cr); 02828 02829 /* reset pointer */ 02830 new_cr=NULL; 02831 } 02832 02833 /* discard partial input */ 02834 /* free memory for current check result record */ 02835 else{ 02836 free_check_result(new_cr); 02837 my_free(new_cr); 02838 } 02839 } 02840 02841 /* free memory and close file */ 02842 my_free(input); 02843 mmap_fclose(thefile); 02844 02845 /* delete the file (as well its ok-to-go file) if it's too old */ 02846 /* other (current) files are deleted later (when results are processed) */ 02847 delete_check_result_file(fname); 02848 02849 return OK; 02850 } 02851 02852 02853 02854 02855 /* deletes as check result file, as well as its ok-to-go file */ 02856 int delete_check_result_file(char *fname){ 02857 char *temp_buffer=NULL; 02858 02859 /* delete the result file */ 02860 unlink(fname); 02861 02862 /* delete the ok-to-go file */ 02863 dummy=asprintf(&temp_buffer,"%s.ok",fname); 02864 unlink(temp_buffer); 02865 my_free(temp_buffer); 02866 02867 return OK; 02868 } 02869 02870 02871 02872 02873 /* reads the first host/service check result from the list in memory */ 02874 check_result *read_check_result(void){ 02875 check_result *first_cr=NULL; 02876 02877 if(check_result_list==NULL) 02878 return NULL; 02879 02880 first_cr=check_result_list; 02881 check_result_list=check_result_list->next; 02882 02883 return first_cr; 02884 } 02885 02886 02887 02888 /* initializes a host/service check result */ 02889 int init_check_result(check_result *info){ 02890 02891 if(info==NULL) 02892 return ERROR; 02893 02894 /* reset vars */ 02895 info->object_check_type=HOST_CHECK; 02896 info->host_name=NULL; 02897 info->service_description=NULL; 02898 info->check_type=HOST_CHECK_ACTIVE; 02899 info->check_options=CHECK_OPTION_NONE; 02900 info->scheduled_check=FALSE; 02901 info->reschedule_check=FALSE; 02902 info->output_file_fp=NULL; 02903 info->output_file_fd=-1; 02904 info->latency=0.0; 02905 info->start_time.tv_sec=0; 02906 info->start_time.tv_usec=0; 02907 info->finish_time.tv_sec=0; 02908 info->finish_time.tv_usec=0; 02909 info->early_timeout=FALSE; 02910 info->exited_ok=TRUE; 02911 info->return_code=0; 02912 info->output=NULL; 02913 info->next=NULL; 02914 02915 return OK; 02916 } 02917 02918 02919 02920 02921 /* adds a new host/service check result to the list in memory */ 02922 int add_check_result_to_list(check_result *new_cr){ 02923 check_result *temp_cr=NULL; 02924 check_result *last_cr=NULL; 02925 02926 if(new_cr==NULL) 02927 return ERROR; 02928 02929 /* add to list, sorted by finish time (asc) */ 02930 02931 /* find insertion point */ 02932 last_cr=check_result_list; 02933 for(temp_cr=check_result_list;temp_cr!=NULL;temp_cr=temp_cr->next){ 02934 if(temp_cr->finish_time.tv_sec >= new_cr->finish_time.tv_sec){ 02935 if(temp_cr->finish_time.tv_sec > new_cr->finish_time.tv_sec) 02936 break; 02937 else if(temp_cr->finish_time.tv_usec > new_cr->finish_time.tv_usec) 02938 break; 02939 } 02940 last_cr=temp_cr; 02941 } 02942 02943 /* item goes at head of list */ 02944 if(check_result_list==NULL || temp_cr==check_result_list){ 02945 new_cr->next=check_result_list; 02946 check_result_list=new_cr; 02947 } 02948 02949 /* item goes in middle or at end of list */ 02950 else{ 02951 new_cr->next=temp_cr; 02952 last_cr->next=new_cr; 02953 } 02954 02955 return OK; 02956 } 02957 02958 02959 02960 02961 /* frees all memory associated with the check result list */ 02962 int free_check_result_list(void){ 02963 check_result *this_cr=NULL; 02964 check_result *next_cr=NULL; 02965 02966 for(this_cr=check_result_list;this_cr!=NULL;this_cr=next_cr){ 02967 next_cr=this_cr->next; 02968 free_check_result(this_cr); 02969 my_free(this_cr); 02970 } 02971 02972 check_result_list=NULL; 02973 02974 return OK; 02975 } 02976 02977 02978 02979 02980 /* frees memory associated with a host/service check result */ 02981 int free_check_result(check_result *info){ 02982 02983 if(info==NULL) 02984 return OK; 02985 02986 my_free(info->host_name); 02987 my_free(info->service_description); 02988 my_free(info->output_file); 02989 my_free(info->output); 02990 02991 return OK; 02992 } 02993 02994 02995 02996 /* parse raw plugin output and return: short and long output, perf data */ 02997 int parse_check_output(char *buf, char **short_output, char **long_output, char **perf_data, int escape_newlines_please, int newlines_are_escaped){ 02998 int current_line=0; 02999 int found_newline=FALSE; 03000 int eof=FALSE; 03001 int used_buf=0; 03002 int dbuf_chunk=1024; 03003 dbuf db1; 03004 dbuf db2; 03005 char *ptr=NULL; 03006 int in_perf_data=FALSE; 03007 char *tempbuf=NULL; 03008 register int x=0; 03009 register int y=0; 03010 03011 /* initialize values */ 03012 if(short_output) 03013 *short_output=NULL; 03014 if(long_output) 03015 *long_output=NULL; 03016 if(perf_data) 03017 *perf_data=NULL; 03018 03019 /* nothing to do */ 03020 if(buf==NULL || !strcmp(buf,"")) 03021 return OK; 03022 03023 used_buf=strlen(buf)+1; 03024 03025 /* initialize dynamic buffers (1KB chunk size) */ 03026 dbuf_init(&db1,dbuf_chunk); 03027 dbuf_init(&db2,dbuf_chunk); 03028 03029 /* unescape newlines and escaped backslashes first */ 03030 if(newlines_are_escaped==TRUE){ 03031 for(x=0,y=0;buf[x]!='\x0';x++){ 03032 if(buf[x]=='\\' && buf[x+1]=='\\'){ 03033 x++; 03034 buf[y++]=buf[x]; 03035 } 03036 else if(buf[x]=='\\' && buf[x+1]=='n'){ 03037 x++; 03038 buf[y++]='\n'; 03039 } 03040 else 03041 buf[y++]=buf[x]; 03042 } 03043 buf[y]='\x0'; 03044 } 03045 03046 /* process each line of input */ 03047 for(x=0;eof==FALSE;x++){ 03048 03049 /* we found the end of a line */ 03050 if(buf[x]=='\n') 03051 found_newline=TRUE; 03052 else if(buf[x]=='\\' && buf[x+1]=='n' && newlines_are_escaped==TRUE){ 03053 found_newline=TRUE; 03054 buf[x]='\x0'; 03055 x++; 03056 } 03057 else if(buf[x]=='\x0'){ 03058 found_newline=TRUE; 03059 eof=TRUE; 03060 } 03061 else 03062 found_newline=FALSE; 03063 03064 if(found_newline==TRUE){ 03065 03066 current_line++; 03067 03068 /* handle this line of input */ 03069 buf[x]='\x0'; 03070 if((tempbuf=(char *)strdup(buf))){ 03071 03072 /* first line contains short plugin output and optional perf data */ 03073 if(current_line==1){ 03074 03075 /* get the short plugin output */ 03076 if((ptr=strtok(tempbuf,"|"))){ 03077 if(short_output) 03078 *short_output=(char *)strdup(ptr); 03079 03080 /* get the optional perf data */ 03081 if((ptr=strtok(NULL,"\n"))) 03082 dbuf_strcat(&db2,ptr); 03083 } 03084 } 03085 03086 /* additional lines contain long plugin output and optional perf data */ 03087 else{ 03088 03089 /* rest of the output is perf data */ 03090 if(in_perf_data==TRUE){ 03091 dbuf_strcat(&db2,tempbuf); 03092 dbuf_strcat(&db2," "); 03093 } 03094 03095 /* we're still in long output */ 03096 else{ 03097 03098 /* perf data separator has been found */ 03099 if(strstr(tempbuf,"|")){ 03100 03101 /* NOTE: strtok() causes problems if first character of tempbuf='|', so use my_strtok() instead */ 03102 /* get the remaining long plugin output */ 03103 if((ptr=my_strtok(tempbuf,"|"))){ 03104 03105 if(current_line>2) 03106 dbuf_strcat(&db1,"\n"); 03107 dbuf_strcat(&db1,ptr); 03108 03109 /* get the perf data */ 03110 if((ptr=my_strtok(NULL,"\n"))){ 03111 dbuf_strcat(&db2,ptr); 03112 dbuf_strcat(&db2," "); 03113 } 03114 } 03115 03116 /* set the perf data flag */ 03117 in_perf_data=TRUE; 03118 } 03119 03120 /* just long output */ 03121 else{ 03122 if(current_line>2) 03123 dbuf_strcat(&db1,"\n"); 03124 dbuf_strcat(&db1,tempbuf); 03125 } 03126 } 03127 } 03128 03129 my_free(tempbuf); 03130 tempbuf=NULL; 03131 } 03132 03133 03134 /* shift data back to front of buffer and adjust counters */ 03135 memmove((void *)&buf[0],(void *)&buf[x+1],(size_t)((int)used_buf-x-1)); 03136 used_buf-=(x+1); 03137 buf[used_buf]='\x0'; 03138 x=-1; 03139 } 03140 } 03141 03142 /* save long output */ 03143 if(long_output && (db1.buf && strcmp(db1.buf,""))){ 03144 03145 if(escape_newlines_please==FALSE) 03146 *long_output=(char *)strdup(db1.buf); 03147 03148 else{ 03149 03150 /* escape newlines (and backslashes) in long output */ 03151 if((tempbuf=(char *)malloc((strlen(db1.buf)*2)+1))){ 03152 03153 for(x=0,y=0;db1.buf[x]!='\x0';x++){ 03154 03155 if(db1.buf[x]=='\n'){ 03156 tempbuf[y++]='\\'; 03157 tempbuf[y++]='n'; 03158 } 03159 else if(db1.buf[x]=='\\'){ 03160 tempbuf[y++]='\\'; 03161 tempbuf[y++]='\\'; 03162 } 03163 else 03164 tempbuf[y++]=db1.buf[x]; 03165 } 03166 03167 tempbuf[y]='\x0'; 03168 *long_output=(char *)strdup(tempbuf); 03169 my_free(tempbuf); 03170 } 03171 } 03172 } 03173 03174 /* save perf data */ 03175 if(perf_data && (db2.buf && strcmp(db2.buf,""))) 03176 *perf_data=(char *)strdup(db2.buf); 03177 03178 /* strip short output and perf data */ 03179 if(short_output) 03180 strip(*short_output); 03181 if(perf_data) 03182 strip(*perf_data); 03183 03184 /* free dynamic buffers */ 03185 dbuf_free(&db1); 03186 dbuf_free(&db2); 03187 03188 return OK; 03189 } 03190 03191 03192 03193 /* creates external command file as a named pipe (FIFO) and opens it for reading (non-blocked mode) */ 03194 int open_command_file(void){ 03195 struct stat st; 03196 int result=0; 03197 03198 /* if we're not checking external commands, don't do anything */ 03199 if(check_external_commands==FALSE) 03200 return OK; 03201 03202 /* the command file was already created */ 03203 if(command_file_created==TRUE) 03204 return OK; 03205 03206 /* reset umask (group needs write permissions) */ 03207 umask(S_IWOTH); 03208 03209 /* use existing FIFO if possible */ 03210 if(!(stat(command_file,&st)!=-1 && (st.st_mode & S_IFIFO))){ 03211 03212 /* create the external command file as a named pipe (FIFO) */ 03213 if((result=mkfifo(command_file,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))!=0){ 03214 03215 logit(NSLOG_RUNTIME_ERROR,TRUE,"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 %s is not running, you should delete this file.\n", command_file, errno, strerror(errno), PROGRAM_NAME); 03216 return ERROR; 03217 } 03218 } 03219 03220 /* open the command file for reading (non-blocked) - O_TRUNC flag cannot be used due to errors on some systems */ 03221 /* NOTE: file must be opened read-write for poll() to work */ 03222 if((command_file_fd=open(command_file,O_RDWR | O_NONBLOCK))<0){ 03223 03224 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Could not open external command file for reading via open(): (%d) -> %s\n",errno,strerror(errno)); 03225 03226 return ERROR; 03227 } 03228 03229 /* re-open the FIFO for use with fgets() */ 03230 if((command_file_fp=(FILE *)fdopen(command_file_fd,"r"))==NULL){ 03231 03232 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Could not open external command file for reading via fdopen(): (%d) -> %s\n",errno,strerror(errno)); 03233 03234 return ERROR; 03235 } 03236 03237 /* initialize worker thread */ 03238 if(init_command_file_worker_thread()==ERROR){ 03239 03240 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Could not initialize command file worker thread.\n"); 03241 03242 /* close the command file */ 03243 fclose(command_file_fp); 03244 03245 /* delete the named pipe */ 03246 unlink(command_file); 03247 03248 return ERROR; 03249 } 03250 03251 /* set a flag to remember we already created the file */ 03252 command_file_created=TRUE; 03253 03254 return OK; 03255 } 03256 03257 03258 /* closes the external command file FIFO and deletes it */ 03259 int close_command_file(void){ 03260 03261 /* if we're not checking external commands, don't do anything */ 03262 if(check_external_commands==FALSE) 03263 return OK; 03264 03265 /* the command file wasn't created or was already cleaned up */ 03266 if(command_file_created==FALSE) 03267 return OK; 03268 03269 /* reset our flag */ 03270 command_file_created=FALSE; 03271 03272 /* close the command file */ 03273 fclose(command_file_fp); 03274 03275 return OK; 03276 } 03277 03278 03279 03280 03281 /******************************************************************/ 03282 /************************ STRING FUNCTIONS ************************/ 03283 /******************************************************************/ 03284 03285 /* gets the next string from a buffer in memory - strings are terminated by newlines, which are removed */ 03286 char *get_next_string_from_buf(char *buf, int *start_index, int bufsize){ 03287 char *sptr=NULL; 03288 char *nl="\n"; 03289 int x; 03290 03291 if(buf==NULL || start_index==NULL) 03292 return NULL; 03293 if(bufsize<0) 03294 return NULL; 03295 if(*start_index >= (bufsize-1)) 03296 return NULL; 03297 03298 sptr=buf+*start_index; 03299 03300 /* end of buffer */ 03301 if(sptr[0]=='\x0') 03302 return NULL; 03303 03304 x=strcspn(sptr,nl); 03305 sptr[x]='\x0'; 03306 03307 *start_index+=x+1; 03308 03309 return sptr; 03310 } 03311 03312 03313 03314 /* determines whether or not an object name (host, service, etc) contains illegal characters */ 03315 int contains_illegal_object_chars(char *name){ 03316 register int x=0; 03317 register int y=0; 03318 register int ch=0; 03319 03320 if(name==NULL) 03321 return FALSE; 03322 03323 x=(int)strlen(name)-1; 03324 03325 for(;x>=0;x--){ 03326 03327 ch=(int)name[x]; 03328 03329 /* illegal user-specified characters */ 03330 if(illegal_object_chars!=NULL) 03331 for(y=0;illegal_object_chars[y];y++) 03332 if(name[x]==illegal_object_chars[y]) 03333 return TRUE; 03334 } 03335 03336 return FALSE; 03337 } 03338 03339 03340 /* escapes newlines in a string */ 03341 char *escape_newlines(char *rawbuf){ 03342 char *newbuf=NULL; 03343 register int x,y; 03344 03345 if(rawbuf==NULL) 03346 return NULL; 03347 03348 /* allocate enough memory to escape all chars if necessary */ 03349 if((newbuf=malloc((strlen(rawbuf)*2)+1))==NULL) 03350 return NULL; 03351 03352 for(x=0,y=0;rawbuf[x]!=(char)'\x0';x++){ 03353 03354 /* escape backslashes */ 03355 if(rawbuf[x]=='\\'){ 03356 newbuf[y++]='\\'; 03357 newbuf[y++]='\\'; 03358 } 03359 03360 /* escape newlines */ 03361 else if(rawbuf[x]=='\n'){ 03362 newbuf[y++]='\\'; 03363 newbuf[y++]='n'; 03364 } 03365 03366 else 03367 newbuf[y++]=rawbuf[x]; 03368 } 03369 newbuf[y]='\x0'; 03370 03371 return newbuf; 03372 } 03373 03374 03375 /* compares strings */ 03376 int compare_strings(char *val1a, char *val2a){ 03377 03378 /* use the compare_hashdata() function */ 03379 return compare_hashdata(val1a,NULL,val2a,NULL); 03380 } 03381 03382 03383 /******************************************************************/ 03384 /************************* FILE FUNCTIONS *************************/ 03385 /******************************************************************/ 03386 03387 /* renames a file - works across filesystems (Mike Wiacek) */ 03388 int my_rename(char *source, char *dest){ 03389 int rename_result=0; 03390 03391 03392 /* make sure we have something */ 03393 if(source==NULL || dest==NULL) 03394 return -1; 03395 03396 /* first see if we can rename file with standard function */ 03397 rename_result=rename(source,dest); 03398 03399 /* handle any errors... */ 03400 if(rename_result==-1){ 03401 03402 /* an error occurred because the source and dest files are on different filesystems */ 03403 if(errno==EXDEV){ 03404 03405 /* try copying the file */ 03406 if(my_fcopy(source,dest)==ERROR){ 03407 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Unable to rename file '%s' to '%s': %s\n",source,dest,strerror(errno)); 03408 return -1; 03409 } 03410 03411 /* delete the original file */ 03412 unlink(source); 03413 03414 /* reset result since we successfully copied file */ 03415 rename_result=0; 03416 } 03417 03418 /* some other error occurred */ 03419 else{ 03420 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Unable to rename file '%s' to '%s': %s\n",source,dest,strerror(errno)); 03421 return rename_result; 03422 } 03423 } 03424 03425 return rename_result; 03426 } 03427 03428 /* 03429 * copy a file from the path at source to the already opened 03430 * destination file dest. 03431 * This is handy when creating tempfiles with mkstemp() 03432 */ 03433 int my_fdcopy(char *source, char *dest, int dest_fd){ 03434 int source_fd, rd_result = 0, wr_result = 0; 03435 unsigned long tot_written = 0, tot_read = 0, buf_size = 0; 03436 struct stat st; 03437 char *buf; 03438 03439 /* open source file for reading */ 03440 if((source_fd=open(source,O_RDONLY,0644)) < 0){ 03441 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Unable to open file '%s' for reading: %s\n",source,strerror(errno)); 03442 return ERROR; 03443 } 03444 03445 /* 03446 * find out how large the source-file is so we can be sure 03447 * we've written all of it 03448 */ 03449 if (fstat(source_fd, &st) < 0) { 03450 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Unable to stat source file '%s' for my_fcopy(): %s\n", source, strerror(errno)); 03451 close(source_fd); 03452 return ERROR; 03453 } 03454 03455 /* 03456 * If the file is huge, read it and write it in chunks. 03457 * This value (128K) is the result of "pick-one-at-random" 03458 * with some minimal testing and may not be optimal for all 03459 * hardware setups, but it should work ok for most. It's 03460 * faster than 1K buffers and 1M buffers, so change at your 03461 * own peril. Note that it's useful to make it fit in the L2 03462 * cache, so larger isn't necessarily better. 03463 */ 03464 buf_size = st.st_size > 128 << 10 ? 128 << 10 : st.st_size; 03465 buf = malloc(buf_size); 03466 if (!buf) { 03467 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Unable to malloc(%lu) bytes: %s\n", buf_size, strerror(errno)); 03468 close(source_fd); 03469 return ERROR; 03470 } 03471 /* most of the times, this loop will be gone through once */ 03472 while (tot_written < st.st_size) { 03473 int loop_wr = 0; 03474 03475 rd_result = read(source_fd, buf, buf_size); 03476 if (rd_result < 0) { 03477 if (errno == EAGAIN || errno == EINTR) 03478 continue; 03479 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: my_fcopy() failed to read from '%s': %s\n", source, strerror(errno)); 03480 break; 03481 } 03482 tot_read += rd_result; 03483 03484 while (loop_wr < rd_result) { 03485 wr_result = write(dest_fd, buf + loop_wr, rd_result - loop_wr); 03486 03487 if (wr_result < 0) { 03488 if (errno == EAGAIN || errno == EINTR) 03489 continue; 03490 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: my_fcopy() failed to write to '%s': %s\n", dest, strerror(errno)); 03491 break; 03492 } 03493 loop_wr += wr_result; 03494 } 03495 if (wr_result < 0) 03496 break; 03497 tot_written += loop_wr; 03498 } 03499 03500 /* 03501 * clean up irregardless of how things went. dest_fd comes from 03502 * our caller, so we mustn't close it. 03503 */ 03504 close(source_fd); 03505 free(buf); 03506 03507 if (rd_result < 0 || wr_result < 0) { 03508 /* don't leave half-written files around */ 03509 unlink(dest); 03510 return ERROR; 03511 } 03512 03513 return OK; 03514 } 03515 03516 03517 /* copies a file */ 03518 int my_fcopy(char *source, char *dest){ 03519 int dest_fd, result; 03520 03521 /* make sure we have something */ 03522 if(source==NULL || dest==NULL) 03523 return ERROR; 03524 03525 /* unlink destination file first (not doing so can cause problems on network file systems like CIFS) */ 03526 unlink(dest); 03527 03528 /* open destination file for writing */ 03529 if((dest_fd=open(dest,O_WRONLY|O_TRUNC|O_CREAT|O_APPEND,0644)) < 0){ 03530 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Unable to open file '%s' for writing: %s\n",dest,strerror(errno)); 03531 return ERROR; 03532 } 03533 03534 result = my_fdcopy(source, dest, dest_fd); 03535 close(dest_fd); 03536 return result; 03537 } 03538 03539 03540 /******************************************************************/ 03541 /******************** DYNAMIC BUFFER FUNCTIONS ********************/ 03542 /******************************************************************/ 03543 03544 /* initializes a dynamic buffer */ 03545 int dbuf_init(dbuf *db, int chunk_size){ 03546 03547 if(db==NULL) 03548 return ERROR; 03549 03550 db->buf=NULL; 03551 db->used_size=0L; 03552 db->allocated_size=0L; 03553 db->chunk_size=chunk_size; 03554 03555 return OK; 03556 } 03557 03558 03559 /* frees a dynamic buffer */ 03560 int dbuf_free(dbuf *db){ 03561 03562 if(db==NULL) 03563 return ERROR; 03564 03565 if(db->buf!=NULL) 03566 my_free(db->buf); 03567 db->buf=NULL; 03568 db->used_size=0L; 03569 db->allocated_size=0L; 03570 03571 return OK; 03572 } 03573 03574 03575 /* dynamically expands a string */ 03576 int dbuf_strcat(dbuf *db, char *buf){ 03577 char *newbuf=NULL; 03578 unsigned long buflen=0L; 03579 unsigned long new_size=0L; 03580 unsigned long memory_needed=0L; 03581 03582 if(db==NULL || buf==NULL) 03583 return ERROR; 03584 03585 /* how much memory should we allocate (if any)? */ 03586 buflen=strlen(buf); 03587 new_size=db->used_size+buflen+1; 03588 03589 /* we need more memory */ 03590 if(db->allocated_size<new_size){ 03591 03592 memory_needed=((ceil(new_size/db->chunk_size)+1)*db->chunk_size); 03593 03594 /* allocate memory to store old and new string */ 03595 if((newbuf=(char *)realloc((void *)db->buf,(size_t)memory_needed))==NULL) 03596 return ERROR; 03597 03598 /* update buffer pointer */ 03599 db->buf=newbuf; 03600 03601 /* update allocated size */ 03602 db->allocated_size=memory_needed; 03603 03604 /* terminate buffer */ 03605 db->buf[db->used_size]='\x0'; 03606 } 03607 03608 /* append the new string */ 03609 strcat(db->buf,buf); 03610 03611 /* update size allocated */ 03612 db->used_size+=buflen; 03613 03614 return OK; 03615 } 03616 03617 03618 03619 /******************************************************************/ 03620 /******************** EMBEDDED PERL FUNCTIONS *********************/ 03621 /******************************************************************/ 03622 03623 /* initializes embedded perl interpreter */ 03624 int init_embedded_perl(char **env){ 03625 #ifdef EMBEDDEDPERL 03626 char **embedding=NULL; 03627 int exitstatus=0; 03628 int argc=2; 03629 struct stat stat_buf; 03630 03631 /* make sure the P1 file exists... */ 03632 if(p1_file==NULL || stat(p1_file,&stat_buf)!=0){ 03633 03634 use_embedded_perl=FALSE; 03635 03636 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: p1.pl file required for embedded Perl interpreter is missing!\n"); 03637 } 03638 03639 else{ 03640 03641 embedding=malloc(2*sizeof(char *)); 03642 if(embedding==NULL) 03643 return ERROR; 03644 *embedding=strdup(""); 03645 *(embedding+1)=strdup(p1_file); 03646 03647 use_embedded_perl=TRUE; 03648 03649 PERL_SYS_INIT3(&argc,&embedding,&env); 03650 03651 if((my_perl=perl_alloc())==NULL){ 03652 use_embedded_perl=FALSE; 03653 logit(NSLOG_RUNTIME_ERROR,TRUE,"Error: Could not allocate memory for embedded Perl interpreter!\n"); 03654 } 03655 } 03656 03657 /* a fatal error occurred... */ 03658 if(use_embedded_perl==FALSE){ 03659 03660 logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR,TRUE,"Bailing out due to errors encountered while initializing the embedded Perl interpreter. (PID=%d)\n",(int)getpid()); 03661 03662 cleanup(); 03663 exit(ERROR); 03664 } 03665 03666 perl_construct(my_perl); 03667 exitstatus=perl_parse(my_perl,xs_init,2,(char **)embedding,env); 03668 if(!exitstatus) 03669 exitstatus=perl_run(my_perl); 03670 03671 #endif 03672 return OK; 03673 } 03674 03675 03676 /* closes embedded perl interpreter */ 03677 int deinit_embedded_perl(void){ 03678 #ifdef EMBEDDEDPERL 03679 03680 PL_perl_destruct_level=0; 03681 perl_destruct(my_perl); 03682 perl_free(my_perl); 03683 PERL_SYS_TERM(); 03684 03685 #endif 03686 return OK; 03687 } 03688 03689 03690 /* checks to see if we should run a script using the embedded Perl interpreter */ 03691 int file_uses_embedded_perl(char *fname){ 03692 int use_epn=FALSE; 03693 #ifdef EMBEDDEDPERL 03694 FILE *fp=NULL; 03695 char line1[80]=""; 03696 char linen[80]=""; 03697 int line=0; 03698 char *ptr=NULL; 03699 int found_epn_directive=FALSE; 03700 03701 if(enable_embedded_perl==TRUE){ 03702 03703 /* open the file, check if its a Perl script and see if we can use epn */ 03704 fp=fopen(fname,"r"); 03705 if(fp!=NULL){ 03706 03707 /* grab the first line - we should see Perl */ 03708 fgets(line1,80,fp); 03709 03710 /* yep, its a Perl script... */ 03711 if(strstr(line1,"/bin/perl")!=NULL){ 03712 03713 /* epn directives must be found in first ten lines of plugin */ 03714 for(line=1;line<10;line++){ 03715 03716 if(fgets(linen,80,fp)){ 03717 03718 /* line contains Icinga directives - keep Nagios compatibility */ 03719 if(strstr(linen,"# nagios:") || strstr(linen,"# icinga:")){ 03720 03721 ptr=strtok(linen,":"); 03722 03723 /* process each directive */ 03724 for(ptr=strtok(NULL,",");ptr!=NULL;ptr=strtok(NULL,",")){ 03725 03726 strip(ptr); 03727 03728 if(!strcmp(ptr,"+epn")){ 03729 use_epn=TRUE; 03730 found_epn_directive=TRUE; 03731 } 03732 else if(!strcmp(ptr,"-epn")){ 03733 use_epn=FALSE; 03734 found_epn_directive=TRUE; 03735 } 03736 } 03737 } 03738 03739 if(found_epn_directive==TRUE) 03740 break; 03741 } 03742 03743 /* EOF */ 03744 else 03745 break; 03746 } 03747 03748 /* if the plugin didn't tell us whether or not to use embedded Perl, use implicit value */ 03749 if(found_epn_directive==FALSE) 03750 use_epn=(use_embedded_perl_implicitly==TRUE)?TRUE:FALSE; 03751 } 03752 03753 fclose(fp); 03754 } 03755 } 03756 #endif 03757 03758 return use_epn; 03759 } 03760 03761 03762 03763 03764 03765 /******************************************************************/ 03766 /************************ THREAD FUNCTIONS ************************/ 03767 /******************************************************************/ 03768 03769 /* initializes command file worker thread */ 03770 int init_command_file_worker_thread(void){ 03771 int result=0; 03772 sigset_t newmask; 03773 03774 /* initialize circular buffer */ 03775 external_command_buffer.head=0; 03776 external_command_buffer.tail=0; 03777 external_command_buffer.items=0; 03778 external_command_buffer.high=0; 03779 external_command_buffer.overflow=0L; 03780 external_command_buffer.buffer=(void **)malloc(external_command_buffer_slots*sizeof(char **)); 03781 if(external_command_buffer.buffer==NULL) 03782 return ERROR; 03783 03784 /* initialize mutex (only on cold startup) */ 03785 if(sigrestart==FALSE) 03786 pthread_mutex_init(&external_command_buffer.buffer_lock,NULL); 03787 03788 /* new thread should block all signals */ 03789 sigfillset(&newmask); 03790 pthread_sigmask(SIG_BLOCK,&newmask,NULL); 03791 03792 /* create worker thread */ 03793 result=pthread_create(&worker_threads[COMMAND_WORKER_THREAD],NULL,command_file_worker_thread,NULL); 03794 03795 /* main thread should unblock all signals */ 03796 pthread_sigmask(SIG_UNBLOCK,&newmask,NULL); 03797 03798 if(result) 03799 return ERROR; 03800 03801 return OK; 03802 } 03803 03804 03805 /* shutdown command file worker thread */ 03806 int shutdown_command_file_worker_thread(void){ 03807 int result=0; 03808 03809 /* 2010-01-04 AE: 03810 * calling pthread_cancel(0) will cause segfaults with some 03811 * thread libraries. It's possible that will happen if the 03812 * user has a number of config files larger than the max 03813 * open file descriptor limit (ulimit -n) and some retarded 03814 * eventbroker module leaks filedescriptors, since we'll then 03815 * enter the cleanup() routine from main() before we've 03816 * spawned any threads. 03817 */ 03818 if (worker_threads[COMMAND_WORKER_THREAD]) { 03819 /* tell the worker thread to exit */ 03820 result=pthread_cancel(worker_threads[COMMAND_WORKER_THREAD]); 03821 03822 /* wait for the worker thread to exit */ 03823 if(result==0){ 03824 result=pthread_join(worker_threads[COMMAND_WORKER_THREAD],NULL); 03825 } 03826 03827 /* we're being called from a fork()'ed child process - can't cancel thread, so just cleanup memory */ 03828 else { 03829 cleanup_command_file_worker_thread(NULL); 03830 } 03831 } 03832 03833 return OK; 03834 } 03835 03836 03837 /* clean up resources used by command file worker thread */ 03838 void cleanup_command_file_worker_thread(void *arg){ 03839 register int x=0; 03840 03841 /* release memory allocated to circular buffer */ 03842 for(x=external_command_buffer.tail;x!=external_command_buffer.head;x=(x+1) % external_command_buffer_slots){ 03843 my_free(((char **)external_command_buffer.buffer)[x]); 03844 } 03845 my_free(external_command_buffer.buffer); 03846 03847 return; 03848 } 03849 03850 03851 03852 /* worker thread - artificially increases buffer of named pipe */ 03853 void * command_file_worker_thread(void *arg){ 03854 char input_buffer[MAX_EXTERNAL_COMMAND_LENGTH]; 03855 struct pollfd pfd; 03856 int pollval; 03857 struct timeval tv; 03858 int buffer_items=0; 03859 int result=0; 03860 03861 /* specify cleanup routine */ 03862 pthread_cleanup_push(cleanup_command_file_worker_thread,NULL); 03863 03864 /* set cancellation info */ 03865 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); 03866 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); 03867 03868 while(1){ 03869 03870 /* should we shutdown? */ 03871 pthread_testcancel(); 03872 03873 /* wait for data to arrive */ 03874 /* select seems to not work, so we have to use poll instead */ 03875 /* 10-15-08 EG check into implementing William's patch @ http://blog.netways.de/2008/08/15/nagios-unter-mac-os-x-installieren/ */ 03876 /* 10-15-08 EG poll() seems broken on OSX - see Jonathan's patch a few lines down */ 03877 pfd.fd=command_file_fd; 03878 pfd.events=POLLIN; 03879 pollval=poll(&pfd,1,500); 03880 03881 /* loop if no data */ 03882 if(pollval==0) 03883 continue; 03884 03885 /* check for errors */ 03886 if(pollval==-1){ 03887 03888 switch(errno){ 03889 case EBADF: 03890 write_to_log("command_file_worker_thread(): poll(): EBADF",logging_options,NULL); 03891 break; 03892 case ENOMEM: 03893 write_to_log("command_file_worker_thread(): poll(): ENOMEM",logging_options,NULL); 03894 break; 03895 case EFAULT: 03896 write_to_log("command_file_worker_thread(): poll(): EFAULT",logging_options,NULL); 03897 break; 03898 case EINTR: 03899 /* this can happen when running under a debugger like gdb */ 03900 /* 03901 write_to_log("command_file_worker_thread(): poll(): EINTR (impossible)",logging_options,NULL); 03902 */ 03903 break; 03904 default: 03905 write_to_log("command_file_worker_thread(): poll(): Unknown errno value.",logging_options,NULL); 03906 break; 03907 } 03908 03909 continue; 03910 } 03911 03912 /* should we shutdown? */ 03913 pthread_testcancel(); 03914 03915 /* get number of items in the buffer */ 03916 pthread_mutex_lock(&external_command_buffer.buffer_lock); 03917 buffer_items=external_command_buffer.items; 03918 pthread_mutex_unlock(&external_command_buffer.buffer_lock); 03919 03920 #ifdef DEBUG_CFWT 03921 printf("(CFWT) BUFFER ITEMS: %d/%d\n",buffer_items,external_command_buffer_slots); 03922 #endif 03923 03924 /* 10-15-08 Fix for OS X by Jonathan Saggau - see http://www.jonathansaggau.com/blog/2008/09/using_shark_and_custom_dtrace.html */ 03925 /* Not sure if this would have negative effects on other OSes... */ 03926 if(buffer_items==0){ 03927 /* pause a bit so OS X doesn't go nuts with CPU overload */ 03928 tv.tv_sec=0; 03929 tv.tv_usec=500; 03930 select(0,NULL,NULL,NULL,&tv); 03931 } 03932 03933 /* process all commands in the file (named pipe) if there's some space in the buffer */ 03934 if(buffer_items<external_command_buffer_slots){ 03935 03936 /* clear EOF condition from prior run (FreeBSD fix) */ 03937 /* FIXME: use_poll_on_cmd_pipe: Still needed? */ 03938 clearerr(command_file_fp); 03939 03940 /* read and process the next command in the file */ 03941 while(fgets(input_buffer,(int)(sizeof(input_buffer)-1),command_file_fp)!=NULL){ 03942 03943 #ifdef DEBUG_CFWT 03944 printf("(CFWT) READ: %s",input_buffer); 03945 #endif 03946 03947 /* submit the external command for processing (retry if buffer is full) */ 03948 while((result=submit_external_command(input_buffer,&buffer_items))==ERROR && buffer_items==external_command_buffer_slots){ 03949 03950 /* wait a bit */ 03951 tv.tv_sec=0; 03952 tv.tv_usec=250000; 03953 select(0,NULL,NULL,NULL,&tv); 03954 03955 /* should we shutdown? */ 03956 pthread_testcancel(); 03957 } 03958 03959 #ifdef DEBUG_CFWT 03960 printf("(CFWT) RES: %d, BUFFER_ITEMS: %d/%d\n",result,buffer_items,external_comand_buffer_slots); 03961 #endif 03962 03963 /* bail if the circular buffer is full */ 03964 if(buffer_items==external_command_buffer_slots) 03965 break; 03966 03967 /* should we shutdown? */ 03968 pthread_testcancel(); 03969 } 03970 } 03971 else { 03972 /* HB 06-07-2009: 03973 * We should wait for the event queuing to catch up some commands 03974 * from the buffer if for this atomic run the buffer is filled completely or 03975 * is overrun 03976 */ 03977 /* wait a bit */ 03978 tv.tv_sec=0; 03979 tv.tv_usec=250000; 03980 select(0,NULL,NULL,NULL,&tv); 03981 03982 /* should we shutdown? */ 03983 pthread_testcancel(); 03984 } 03985 } 03986 03987 /* removes cleanup handler - this should never be reached */ 03988 pthread_cleanup_pop(0); 03989 03990 return NULL; 03991 } 03992 03993 03994 03995 /* submits an external command for processing */ 03996 int submit_external_command(char *cmd, int *buffer_items){ 03997 int result=OK; 03998 03999 if(cmd==NULL || external_command_buffer.buffer==NULL){ 04000 if(buffer_items!=NULL) 04001 *buffer_items=-1; 04002 return ERROR; 04003 } 04004 04005 /* obtain a lock for writing to the buffer */ 04006 pthread_mutex_lock(&external_command_buffer.buffer_lock); 04007 04008 if(external_command_buffer.items<external_command_buffer_slots){ 04009 04010 /* save the line in the buffer */ 04011 ((char **)external_command_buffer.buffer)[external_command_buffer.head]=(char *)strdup(cmd); 04012 04013 /* increment the head counter and items */ 04014 external_command_buffer.head=(external_command_buffer.head + 1) % external_command_buffer_slots; 04015 external_command_buffer.items++; 04016 if(external_command_buffer.items>external_command_buffer.high) 04017 external_command_buffer.high=external_command_buffer.items; 04018 } 04019 04020 /* buffer was full */ 04021 else 04022 result=ERROR; 04023 04024 /* return number of items now in buffer */ 04025 if(buffer_items!=NULL) 04026 *buffer_items=external_command_buffer.items; 04027 04028 /* release lock on buffer */ 04029 pthread_mutex_unlock(&external_command_buffer.buffer_lock); 04030 04031 return result; 04032 } 04033 04034 04035 04036 /* submits a raw external command (without timestamp) for processing */ 04037 int submit_raw_external_command(char *cmd, time_t *ts, int *buffer_items){ 04038 char *newcmd=NULL; 04039 int result=OK; 04040 time_t timestamp; 04041 04042 if(cmd==NULL) 04043 return ERROR; 04044 04045 /* get the time */ 04046 if(ts!=NULL) 04047 timestamp=*ts; 04048 else 04049 time(×tamp); 04050 04051 /* create the command string */ 04052 dummy=asprintf(&newcmd,"[%lu] %s",(unsigned long)timestamp,cmd); 04053 04054 /* submit the command */ 04055 result=submit_external_command(newcmd,buffer_items); 04056 04057 /* free allocated memory */ 04058 my_free(newcmd); 04059 04060 return result; 04061 } 04062 04063 04064 04065 /******************************************************************/ 04066 /********************** CHECK STATS FUNCTIONS *********************/ 04067 /******************************************************************/ 04068 04069 /* initialize check statistics data structures */ 04070 int init_check_stats(void){ 04071 int x=0; 04072 int y=0; 04073 04074 for(x=0;x<MAX_CHECK_STATS_TYPES;x++){ 04075 check_statistics[x].current_bucket=0; 04076 for(y=0;y<CHECK_STATS_BUCKETS;y++) 04077 check_statistics[x].bucket[y]=0; 04078 check_statistics[x].overflow_bucket=0; 04079 for(y=0;y<3;y++) 04080 check_statistics[x].minute_stats[y]=0; 04081 check_statistics[x].last_update=(time_t)0L; 04082 } 04083 04084 return OK; 04085 } 04086 04087 04088 /* records stats for a given type of check */ 04089 int update_check_stats(int check_type, time_t check_time){ 04090 time_t current_time; 04091 unsigned long minutes=0L; 04092 int new_current_bucket=0; 04093 int this_bucket=0; 04094 int x=0; 04095 04096 if(check_type<0 || check_type>=MAX_CHECK_STATS_TYPES) 04097 return ERROR; 04098 04099 time(¤t_time); 04100 04101 if((unsigned long)check_time==0L){ 04102 #ifdef DEBUG_CHECK_STATS 04103 printf("TYPE[%d] CHECK TIME==0!\n",check_type); 04104 #endif 04105 check_time=current_time; 04106 } 04107 04108 /* do some sanity checks on the age of the stats data before we start... */ 04109 /* get the new current bucket number */ 04110 minutes=((unsigned long)check_time-(unsigned long)program_start) / 60; 04111 new_current_bucket=minutes % CHECK_STATS_BUCKETS; 04112 04113 /* its been more than 15 minutes since stats were updated, so clear the stats */ 04114 if((((unsigned long)current_time - (unsigned long)check_statistics[check_type].last_update) / 60) > CHECK_STATS_BUCKETS){ 04115 for(x=0;x<CHECK_STATS_BUCKETS;x++) 04116 check_statistics[check_type].bucket[x]=0; 04117 check_statistics[check_type].overflow_bucket=0; 04118 #ifdef DEBUG_CHECK_STATS 04119 printf("CLEARING ALL: TYPE[%d], CURRENT=%lu, LASTUPDATE=%lu\n",check_type,(unsigned long)current_time,(unsigned long)check_statistics[check_type].last_update); 04120 #endif 04121 } 04122 04123 /* different current bucket number than last time */ 04124 else if(new_current_bucket!=check_statistics[check_type].current_bucket){ 04125 04126 /* clear stats in buckets between last current bucket and new current bucket - stats haven't been updated in a while */ 04127 for(x=check_statistics[check_type].current_bucket;x<(CHECK_STATS_BUCKETS * 2);x++){ 04128 04129 this_bucket=(x + CHECK_STATS_BUCKETS + 1) % CHECK_STATS_BUCKETS; 04130 04131 if(this_bucket==new_current_bucket) 04132 break; 04133 04134 #ifdef DEBUG_CHECK_STATS 04135 printf("CLEARING BUCKET %d, (NEW=%d, OLD=%d)\n",this_bucket,new_current_bucket,check_statistics[check_type].current_bucket); 04136 #endif 04137 04138 /* clear old bucket value */ 04139 check_statistics[check_type].bucket[this_bucket]=0; 04140 } 04141 04142 /* update the current bucket number, push old value to overflow bucket */ 04143 check_statistics[check_type].overflow_bucket=check_statistics[check_type].bucket[new_current_bucket]; 04144 check_statistics[check_type].current_bucket=new_current_bucket; 04145 check_statistics[check_type].bucket[new_current_bucket]=0; 04146 } 04147 #ifdef DEBUG_CHECK_STATS 04148 else 04149 printf("NO CLEARING NEEDED\n"); 04150 #endif 04151 04152 04153 /* increment the value of the current bucket */ 04154 check_statistics[check_type].bucket[new_current_bucket]++; 04155 04156 #ifdef DEBUG_CHECK_STATS 04157 printf("TYPE[%d].BUCKET[%d]=%d\n",check_type,new_current_bucket,check_statistics[check_type].bucket[new_current_bucket]); 04158 printf(" "); 04159 for(x=0;x<CHECK_STATS_BUCKETS;x++) 04160 printf("[%d] ",check_statistics[check_type].bucket[x]); 04161 printf(" (%d)\n",check_statistics[check_type].overflow_bucket); 04162 #endif 04163 04164 /* record last update time */ 04165 check_statistics[check_type].last_update=current_time; 04166 04167 return OK; 04168 } 04169 04170 04171 /* generate 1/5/15 minute stats for a given type of check */ 04172 int generate_check_stats(void){ 04173 time_t current_time; 04174 int x=0; 04175 int new_current_bucket=0; 04176 int this_bucket=0; 04177 int last_bucket=0; 04178 int this_bucket_value=0; 04179 int last_bucket_value=0; 04180 int bucket_value=0; 04181 int seconds=0; 04182 int minutes=0; 04183 int check_type=0; 04184 float this_bucket_weight=0.0; 04185 float last_bucket_weight=0.0; 04186 int left_value=0; 04187 int right_value=0; 04188 04189 04190 time(¤t_time); 04191 04192 /* do some sanity checks on the age of the stats data before we start... */ 04193 /* get the new current bucket number */ 04194 minutes=((unsigned long)current_time-(unsigned long)program_start) / 60; 04195 new_current_bucket=minutes % CHECK_STATS_BUCKETS; 04196 for(check_type=0;check_type<MAX_CHECK_STATS_TYPES;check_type++){ 04197 04198 /* its been more than 15 minutes since stats were updated, so clear the stats */ 04199 if((((unsigned long)current_time - (unsigned long)check_statistics[check_type].last_update) / 60) > CHECK_STATS_BUCKETS){ 04200 for(x=0;x<CHECK_STATS_BUCKETS;x++) 04201 check_statistics[check_type].bucket[x]=0; 04202 check_statistics[check_type].overflow_bucket=0; 04203 #ifdef DEBUG_CHECK_STATS 04204 printf("GEN CLEARING ALL: TYPE[%d], CURRENT=%lu, LASTUPDATE=%lu\n",check_type,(unsigned long)current_time,(unsigned long)check_statistics[check_type].last_update); 04205 #endif 04206 } 04207 04208 /* different current bucket number than last time */ 04209 else if(new_current_bucket!=check_statistics[check_type].current_bucket){ 04210 04211 /* clear stats in buckets between last current bucket and new current bucket - stats haven't been updated in a while */ 04212 for(x=check_statistics[check_type].current_bucket;x<(CHECK_STATS_BUCKETS*2);x++){ 04213 04214 this_bucket=(x + CHECK_STATS_BUCKETS + 1) % CHECK_STATS_BUCKETS; 04215 04216 if(this_bucket==new_current_bucket) 04217 break; 04218 04219 #ifdef DEBUG_CHECK_STATS 04220 printf("GEN CLEARING BUCKET %d, (NEW=%d, OLD=%d), CURRENT=%lu, LASTUPDATE=%lu\n",this_bucket,new_current_bucket,check_statistics[check_type].current_bucket,(unsigned long)current_time,(unsigned long)check_statistics[check_type].last_update); 04221 #endif 04222 04223 /* clear old bucket value */ 04224 check_statistics[check_type].bucket[this_bucket]=0; 04225 } 04226 04227 /* update the current bucket number, push old value to overflow bucket */ 04228 check_statistics[check_type].overflow_bucket=check_statistics[check_type].bucket[new_current_bucket]; 04229 check_statistics[check_type].current_bucket=new_current_bucket; 04230 check_statistics[check_type].bucket[new_current_bucket]=0; 04231 } 04232 #ifdef DEBUG_CHECK_STATS 04233 else 04234 printf("GEN NO CLEARING NEEDED: TYPE[%d], CURRENT=%lu, LASTUPDATE=%lu\n",check_type,(unsigned long)current_time,(unsigned long)check_statistics[check_type].last_update); 04235 #endif 04236 04237 /* update last check time */ 04238 check_statistics[check_type].last_update=current_time; 04239 } 04240 04241 /* determine weights to use for this/last buckets */ 04242 seconds=((unsigned long)current_time-(unsigned long)program_start) % 60; 04243 this_bucket_weight=(seconds/60.0); 04244 last_bucket_weight=((60-seconds)/60.0); 04245 04246 /* update statistics for all check types */ 04247 for(check_type=0;check_type<MAX_CHECK_STATS_TYPES;check_type++){ 04248 04249 /* clear the old statistics */ 04250 for(x=0;x<3;x++) 04251 check_statistics[check_type].minute_stats[x]=0; 04252 04253 /* loop through each bucket */ 04254 for(x=0;x<CHECK_STATS_BUCKETS;x++){ 04255 04256 /* which buckets should we use for this/last bucket? */ 04257 this_bucket=(check_statistics[check_type].current_bucket + CHECK_STATS_BUCKETS - x) % CHECK_STATS_BUCKETS; 04258 last_bucket=(this_bucket + CHECK_STATS_BUCKETS - 1) % CHECK_STATS_BUCKETS; 04259 04260 /* raw/unweighted value for this bucket */ 04261 this_bucket_value=check_statistics[check_type].bucket[this_bucket]; 04262 04263 /* raw/unweighted value for last bucket - use overflow bucket if last bucket is current bucket */ 04264 if(last_bucket==check_statistics[check_type].current_bucket) 04265 last_bucket_value=check_statistics[check_type].overflow_bucket; 04266 else 04267 last_bucket_value=check_statistics[check_type].bucket[last_bucket]; 04268 04269 /* determine value by weighting this/last buckets... */ 04270 /* if this is the current bucket, use its full value + weighted % of last bucket */ 04271 if(x==0){ 04272 right_value=this_bucket_value; 04273 left_value=(int)floor(last_bucket_value * last_bucket_weight); 04274 bucket_value=(int)(this_bucket_value + floor(last_bucket_value * last_bucket_weight)); 04275 } 04276 /* otherwise use weighted % of this and last bucket */ 04277 else{ 04278 right_value=(int)ceil(this_bucket_value * this_bucket_weight); 04279 left_value=(int)floor(last_bucket_value * last_bucket_weight); 04280 bucket_value=(int)(ceil(this_bucket_value * this_bucket_weight) + floor(last_bucket_value * last_bucket_weight)); 04281 } 04282 04283 /* 1 minute stats */ 04284 if(x==0) 04285 check_statistics[check_type].minute_stats[0]=bucket_value; 04286 04287 /* 5 minute stats */ 04288 if(x<5) 04289 check_statistics[check_type].minute_stats[1]+=bucket_value; 04290 04291 /* 15 minute stats */ 04292 if(x<15) 04293 check_statistics[check_type].minute_stats[2]+=bucket_value; 04294 04295 #ifdef DEBUG_CHECK_STATS2 04296 printf("X=%d, THIS[%d]=%d, LAST[%d]=%d, 1/5/15=%d,%d,%d L=%d R=%d\n",x,this_bucket,this_bucket_value,last_bucket,last_bucket_value,check_statistics[check_type].minute_stats[0],check_statistics[check_type].minute_stats[1],check_statistics[check_type].minute_stats[2],left_value,right_value); 04297 #endif 04298 /* record last update time */ 04299 check_statistics[check_type].last_update=current_time; 04300 } 04301 04302 #ifdef DEBUG_CHECK_STATS 04303 printf("TYPE[%d] 1/5/15 = %d, %d, %d (seconds=%d, this_weight=%f, last_weight=%f)\n",check_type,check_statistics[check_type].minute_stats[0],check_statistics[check_type].minute_stats[1],check_statistics[check_type].minute_stats[2],seconds,this_bucket_weight,last_bucket_weight); 04304 #endif 04305 } 04306 04307 return OK; 04308 } 04309 04310 04311 /******************************************************************/ 04312 /************************* MISC FUNCTIONS *************************/ 04313 /******************************************************************/ 04314 04315 /* returns Icinga version */ 04316 char *get_program_version(void){ 04317 04318 return (char *)PROGRAM_VERSION; 04319 } 04320 04321 04322 /* returns Icinga modification date */ 04323 char *get_program_modification_date(void){ 04324 04325 return (char *)PROGRAM_MODIFICATION_DATE; 04326 } 04327 04328 int has_shell_metachars(const char *s){ 04329 if (strpbrk(s,"!$^&*()~[]\\|{};<>?'\"")) 04330 return 1; 04331 else 04332 return 0; 04333 } 04334 04335 04336 /******************************************************************/ 04337 /*********************** CLEANUP FUNCTIONS ************************/ 04338 /******************************************************************/ 04339 04340 /* do some cleanup before we exit */ 04341 void cleanup(void){ 04342 04343 #ifdef USE_EVENT_BROKER 04344 /* unload modules */ 04345 if(test_scheduling==FALSE && verify_config==FALSE){ 04346 neb_free_callback_list(); 04347 neb_unload_all_modules(NEBMODULE_FORCE_UNLOAD,(sigshutdown==TRUE)?NEBMODULE_NEB_SHUTDOWN:NEBMODULE_NEB_RESTART); 04348 neb_free_module_list(); 04349 neb_deinit_modules(); 04350 } 04351 #endif 04352 04353 /* free all allocated memory - including macros */ 04354 free_memory(get_global_macros()); 04355 04356 return; 04357 } 04358 04359 04360 /* free the memory allocated to the linked lists */ 04361 void free_memory(icinga_macros *mac){ 04362 timed_event *this_event=NULL; 04363 timed_event *next_event=NULL; 04364 04365 /* free all allocated memory for the object definitions */ 04366 free_object_data(); 04367 04368 /* free memory allocated to comments */ 04369 free_comment_data(); 04370 04371 /* free check result list */ 04372 free_check_result_list(); 04373 04374 /* free memory for the high priority event list */ 04375 this_event=event_list_high; 04376 while(this_event!=NULL){ 04377 next_event=this_event->next; 04378 my_free(this_event); 04379 this_event=next_event; 04380 } 04381 04382 /* reset the event pointer */ 04383 event_list_high=NULL; 04384 04385 /* free memory for the low priority event list */ 04386 this_event=event_list_low; 04387 while(this_event!=NULL){ 04388 next_event=this_event->next; 04389 my_free(this_event); 04390 this_event=next_event; 04391 } 04392 04393 /* reset the event pointer */ 04394 event_list_low=NULL; 04395 04396 /* free memory for global event handlers */ 04397 my_free(global_host_event_handler); 04398 my_free(global_service_event_handler); 04399 04400 /* free any notification list that may have been overlooked */ 04401 free_notification_list(); 04402 04403 /* free obsessive compulsive commands */ 04404 my_free(ocsp_command); 04405 my_free(ochp_command); 04406 04407 /* 04408 * free memory associated with macros. 04409 * It's ok to only free the volatile ones, as the non-volatile 04410 * are always free()'d before assignment if they're set. 04411 * Doing a full free of them here means we'll wipe the constant 04412 * macros when we get a reload or restart request through the 04413 * command pipe, or when we receive a SIGHUP. 04414 */ 04415 clear_volatile_macros_r(mac); 04416 04417 free_macrox_names(); 04418 04419 /* free illegal char strings */ 04420 my_free(illegal_object_chars); 04421 my_free(illegal_output_chars); 04422 04423 /* free Icinga user and group */ 04424 my_free(nagios_user); 04425 my_free(nagios_group); 04426 04427 /* free file/path variables */ 04428 my_free(log_file); 04429 my_free(debug_file); 04430 my_free(temp_file); 04431 my_free(temp_path); 04432 my_free(check_result_path); 04433 my_free(command_file); 04434 my_free(lock_file); 04435 my_free(auth_file); 04436 my_free(p1_file); 04437 my_free(log_archive_path); 04438 04439 return; 04440 } 04441 04442 04443 /* free a notification list that was created */ 04444 void free_notification_list(void){ 04445 notification *temp_notification=NULL; 04446 notification *next_notification=NULL; 04447 04448 temp_notification=notification_list; 04449 while(temp_notification!=NULL){ 04450 next_notification=temp_notification->next; 04451 my_free(temp_notification); 04452 temp_notification=next_notification; 04453 } 04454 04455 /* reset notification list pointer */ 04456 notification_list=NULL; 04457 04458 return; 04459 } 04460 04461 04462 /* reset all system-wide variables, so when we've receive a SIGHUP we can restart cleanly */ 04463 int reset_variables(void){ 04464 04465 log_file=(char *)strdup(DEFAULT_LOG_FILE); 04466 temp_file=(char *)strdup(DEFAULT_TEMP_FILE); 04467 temp_path=(char *)strdup(DEFAULT_TEMP_PATH); 04468 check_result_path=(char *)strdup(DEFAULT_CHECK_RESULT_PATH); 04469 command_file=(char *)strdup(DEFAULT_COMMAND_FILE); 04470 lock_file=(char *)strdup(DEFAULT_LOCK_FILE); 04471 auth_file=(char *)strdup(DEFAULT_AUTH_FILE); 04472 p1_file=(char *)strdup(DEFAULT_P1_FILE); 04473 log_archive_path=(char *)strdup(DEFAULT_LOG_ARCHIVE_PATH); 04474 debug_file=(char *)strdup(DEFAULT_DEBUG_FILE); 04475 04476 nagios_user=(char *)strdup(DEFAULT_ICINGA_USER); 04477 nagios_group=(char *)strdup(DEFAULT_ICINGA_GROUP); 04478 04479 use_regexp_matches=FALSE; 04480 use_true_regexp_matching=FALSE; 04481 04482 use_daemon_log=DEFAULT_USE_DAEMON_LOG; 04483 04484 use_syslog=DEFAULT_USE_SYSLOG; 04485 use_syslog_local_facility=DEFAULT_USE_SYSLOG_LOCAL_FACILITY; 04486 syslog_local_facility=DEFAULT_SYSLOG_LOCAL_FACILITY; 04487 log_service_retries=DEFAULT_LOG_SERVICE_RETRIES; 04488 log_host_retries=DEFAULT_LOG_HOST_RETRIES; 04489 log_initial_states=DEFAULT_LOG_INITIAL_STATES; 04490 04491 log_notifications=DEFAULT_NOTIFICATION_LOGGING; 04492 log_event_handlers=DEFAULT_LOG_EVENT_HANDLERS; 04493 log_external_commands=DEFAULT_LOG_EXTERNAL_COMMANDS; 04494 log_external_commands_user=DEFAULT_LOG_EXTERNAL_COMMANDS_USER; 04495 log_passive_checks=DEFAULT_LOG_PASSIVE_CHECKS; 04496 04497 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; 04498 04499 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; 04500 04501 service_check_timeout=DEFAULT_SERVICE_CHECK_TIMEOUT; 04502 host_check_timeout=DEFAULT_HOST_CHECK_TIMEOUT; 04503 event_handler_timeout=DEFAULT_EVENT_HANDLER_TIMEOUT; 04504 notification_timeout=DEFAULT_NOTIFICATION_TIMEOUT; 04505 ocsp_timeout=DEFAULT_OCSP_TIMEOUT; 04506 ochp_timeout=DEFAULT_OCHP_TIMEOUT; 04507 04508 sleep_time=DEFAULT_SLEEP_TIME; 04509 interval_length=DEFAULT_INTERVAL_LENGTH; 04510 service_inter_check_delay_method=ICD_SMART; 04511 host_inter_check_delay_method=ICD_SMART; 04512 service_interleave_factor_method=ILF_SMART; 04513 max_service_check_spread=DEFAULT_SERVICE_CHECK_SPREAD; 04514 max_host_check_spread=DEFAULT_HOST_CHECK_SPREAD; 04515 04516 use_aggressive_host_checking=DEFAULT_AGGRESSIVE_HOST_CHECKING; 04517 cached_host_check_horizon=DEFAULT_CACHED_HOST_CHECK_HORIZON; 04518 cached_service_check_horizon=DEFAULT_CACHED_SERVICE_CHECK_HORIZON; 04519 enable_predictive_host_dependency_checks=DEFAULT_ENABLE_PREDICTIVE_HOST_DEPENDENCY_CHECKS; 04520 enable_predictive_service_dependency_checks=DEFAULT_ENABLE_PREDICTIVE_SERVICE_DEPENDENCY_CHECKS; 04521 04522 soft_state_dependencies=FALSE; 04523 04524 retain_state_information=FALSE; 04525 retention_update_interval=DEFAULT_RETENTION_UPDATE_INTERVAL; 04526 use_retained_program_state=TRUE; 04527 use_retained_scheduling_info=FALSE; 04528 retention_scheduling_horizon=DEFAULT_RETENTION_SCHEDULING_HORIZON; 04529 modified_host_process_attributes=MODATTR_NONE; 04530 modified_service_process_attributes=MODATTR_NONE; 04531 retained_host_attribute_mask=0L; 04532 retained_service_attribute_mask=0L; 04533 retained_process_host_attribute_mask=0L; 04534 retained_process_service_attribute_mask=0L; 04535 retained_contact_host_attribute_mask=0L; 04536 retained_contact_service_attribute_mask=0L; 04537 04538 command_check_interval=DEFAULT_COMMAND_CHECK_INTERVAL; 04539 check_reaper_interval=DEFAULT_CHECK_REAPER_INTERVAL; 04540 max_check_reaper_time=DEFAULT_MAX_REAPER_TIME; 04541 max_check_result_file_age=DEFAULT_MAX_CHECK_RESULT_AGE; 04542 service_freshness_check_interval=DEFAULT_FRESHNESS_CHECK_INTERVAL; 04543 host_freshness_check_interval=DEFAULT_FRESHNESS_CHECK_INTERVAL; 04544 auto_rescheduling_interval=DEFAULT_AUTO_RESCHEDULING_INTERVAL; 04545 auto_rescheduling_window=DEFAULT_AUTO_RESCHEDULING_WINDOW; 04546 04547 check_external_commands=DEFAULT_CHECK_EXTERNAL_COMMANDS; 04548 check_orphaned_services=DEFAULT_CHECK_ORPHANED_SERVICES; 04549 check_orphaned_hosts=DEFAULT_CHECK_ORPHANED_HOSTS; 04550 check_service_freshness=DEFAULT_CHECK_SERVICE_FRESHNESS; 04551 check_host_freshness=DEFAULT_CHECK_HOST_FRESHNESS; 04552 auto_reschedule_checks=DEFAULT_AUTO_RESCHEDULE_CHECKS; 04553 04554 log_rotation_method=LOG_ROTATION_NONE; 04555 04556 last_command_check=0L; 04557 last_command_status_update=0L; 04558 last_log_rotation=0L; 04559 04560 max_parallel_service_checks=DEFAULT_MAX_PARALLEL_SERVICE_CHECKS; 04561 currently_running_service_checks=0; 04562 04563 enable_notifications=TRUE; 04564 execute_service_checks=TRUE; 04565 accept_passive_service_checks=TRUE; 04566 execute_host_checks=TRUE; 04567 accept_passive_service_checks=TRUE; 04568 enable_event_handlers=TRUE; 04569 obsess_over_services=FALSE; 04570 obsess_over_hosts=FALSE; 04571 enable_failure_prediction=TRUE; 04572 04573 next_comment_id=0L; /* comment and downtime id get initialized to nonzero elsewhere */ 04574 next_downtime_id=0L; 04575 next_event_id=1; 04576 next_notification_id=1; 04577 04578 aggregate_status_updates=TRUE; 04579 status_update_interval=DEFAULT_STATUS_UPDATE_INTERVAL; 04580 04581 event_broker_options=BROKER_NOTHING; 04582 04583 time_change_threshold=DEFAULT_TIME_CHANGE_THRESHOLD; 04584 04585 enable_flap_detection=DEFAULT_ENABLE_FLAP_DETECTION; 04586 low_service_flap_threshold=DEFAULT_LOW_SERVICE_FLAP_THRESHOLD; 04587 high_service_flap_threshold=DEFAULT_HIGH_SERVICE_FLAP_THRESHOLD; 04588 low_host_flap_threshold=DEFAULT_LOW_HOST_FLAP_THRESHOLD; 04589 high_host_flap_threshold=DEFAULT_HIGH_HOST_FLAP_THRESHOLD; 04590 04591 process_performance_data=DEFAULT_PROCESS_PERFORMANCE_DATA; 04592 04593 translate_passive_host_checks=DEFAULT_TRANSLATE_PASSIVE_HOST_CHECKS; 04594 passive_host_checks_are_soft=DEFAULT_PASSIVE_HOST_CHECKS_SOFT; 04595 04596 use_large_installation_tweaks=DEFAULT_USE_LARGE_INSTALLATION_TWEAKS; 04597 enable_environment_macros=TRUE; 04598 free_child_process_memory=-1; 04599 child_processes_fork_twice=-1; 04600 04601 additional_freshness_latency=DEFAULT_ADDITIONAL_FRESHNESS_LATENCY; 04602 04603 enable_embedded_perl=DEFAULT_ENABLE_EMBEDDED_PERL; 04604 use_embedded_perl_implicitly=DEFAULT_USE_EMBEDDED_PERL_IMPLICITLY; 04605 04606 stalking_event_handlers_for_hosts=DEFAULT_STALKING_EVENT_HANDLERS_FOR_HOSTS; 04607 stalking_event_handlers_for_services=DEFAULT_STALKING_EVENT_HANDLERS_FOR_SERVICES; 04608 04609 external_command_buffer_slots=DEFAULT_EXTERNAL_COMMAND_BUFFER_SLOTS; 04610 04611 debug_level=DEFAULT_DEBUG_LEVEL; 04612 debug_verbosity=DEFAULT_DEBUG_VERBOSITY; 04613 max_debug_file_size=DEFAULT_MAX_DEBUG_FILE_SIZE; 04614 04615 date_format=DATE_FORMAT_US; 04616 04617 /* initialize macros */ 04618 init_macros(); 04619 04620 global_host_event_handler=NULL; 04621 global_service_event_handler=NULL; 04622 global_host_event_handler_ptr=NULL; 04623 global_service_event_handler_ptr=NULL; 04624 04625 ocsp_command=NULL; 04626 ochp_command=NULL; 04627 ocsp_command_ptr=NULL; 04628 ochp_command_ptr=NULL; 04629 04630 /* reset umask */ 04631 umask(S_IWGRP|S_IWOTH); 04632 04633 return OK; 04634 } 04635