Icinga-core 1.4.0
next gen monitoring
base/utils.c
Go to the documentation of this file.
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(&current_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(&current_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(&current_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(&current_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(&current_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(&current_time);
02105         t = localtime_r(&current_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(&current_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(&timestamp);
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(&current_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(&current_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 
 All Data Structures Files Functions Variables Typedefs Defines