/**************************************************************************
*
* AVAIL.C - Nagios Availability CGI
*
* Copyright (c) 2000-2007 Ethan Galstad (nagios@nagios.org)
* Last Modified: 10-21-2007
*
* License:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*************************************************************************/
#include "../include/config.h"
#include "../include/common.h"
#include "../include/objects.h"
#include "../include/comments.h"
#include "../include/statusdata.h"
#include "../include/cgiutils.h"
#include "../include/cgiauth.h"
#include "../include/getcgi.h"
extern char main_config_file[MAX_FILENAME_LENGTH];
extern char url_images_path[MAX_FILENAME_LENGTH];
extern char url_stylesheets_path[MAX_FILENAME_LENGTH];
extern host *host_list;
extern hostgroup *hostgroup_list;
extern servicegroup *servicegroup_list;
extern service *service_list;
extern timeperiod *timeperiod_list;
extern int log_rotation_method;
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
/* output types */
#define HTML_OUTPUT 0
#define CSV_OUTPUT 1
/* archived state types */
#define AS_CURRENT_STATE -1 /* special case for initial assumed state */
#define AS_NO_DATA 0
#define AS_PROGRAM_END 1
#define AS_PROGRAM_START 2
#define AS_HOST_UP 3
#define AS_HOST_DOWN 4
#define AS_HOST_UNREACHABLE 5
#define AS_SVC_OK 6
#define AS_SVC_UNKNOWN 7
#define AS_SVC_WARNING 8
#define AS_SVC_CRITICAL 9
#define AS_SVC_DOWNTIME_START 10
#define AS_SVC_DOWNTIME_END 11
#define AS_HOST_DOWNTIME_START 12
#define AS_HOST_DOWNTIME_END 13
#define AS_SOFT_STATE 1
#define AS_HARD_STATE 2
/* display types */
#define DISPLAY_NO_AVAIL 0
#define DISPLAY_HOSTGROUP_AVAIL 1
#define DISPLAY_HOST_AVAIL 2
#define DISPLAY_SERVICE_AVAIL 3
#define DISPLAY_SERVICEGROUP_AVAIL 4
/* subject types */
#define HOST_SUBJECT 0
#define SERVICE_SUBJECT 1
/* standard report times */
#define TIMEPERIOD_CUSTOM 0
#define TIMEPERIOD_TODAY 1
#define TIMEPERIOD_YESTERDAY 2
#define TIMEPERIOD_THISWEEK 3
#define TIMEPERIOD_LASTWEEK 4
#define TIMEPERIOD_THISMONTH 5
#define TIMEPERIOD_LASTMONTH 6
#define TIMEPERIOD_THISQUARTER 7
#define TIMEPERIOD_LASTQUARTER 8
#define TIMEPERIOD_THISYEAR 9
#define TIMEPERIOD_LASTYEAR 10
#define TIMEPERIOD_LAST24HOURS 11
#define TIMEPERIOD_LAST7DAYS 12
#define TIMEPERIOD_LAST31DAYS 13
#define MIN_TIMESTAMP_SPACING 10
#define MAX_ARCHIVE_SPREAD 65
#define MAX_ARCHIVE 65
#define MAX_ARCHIVE_BACKTRACKS 60
authdata current_authdata;
typedef struct archived_state_struct{
time_t time_stamp;
int entry_type;
int state_type;
char *state_info;
int processed_state;
struct archived_state_struct *misc_ptr;
struct archived_state_struct *next;
}archived_state;
typedef struct avail_subject_struct{
int type;
char *host_name;
char *service_description;
archived_state *as_list; /* archived state list */
archived_state *as_list_tail;
archived_state *sd_list; /* scheduled downtime list */
int last_known_state;
time_t earliest_time;
time_t latest_time;
int earliest_state;
int latest_state;
unsigned long time_up;
unsigned long time_down;
unsigned long time_unreachable;
unsigned long time_ok;
unsigned long time_warning;
unsigned long time_unknown;
unsigned long time_critical;
unsigned long scheduled_time_up;
unsigned long scheduled_time_down;
unsigned long scheduled_time_unreachable;
unsigned long scheduled_time_ok;
unsigned long scheduled_time_warning;
unsigned long scheduled_time_unknown;
unsigned long scheduled_time_critical;
unsigned long scheduled_time_indeterminate;
unsigned long time_indeterminate_nodata;
unsigned long time_indeterminate_notrunning;
struct avail_subject_struct *next;
}avail_subject;
avail_subject *subject_list=NULL;
time_t t1;
time_t t2;
int display_type=DISPLAY_NO_AVAIL;
int timeperiod_type=TIMEPERIOD_LAST24HOURS;
int show_log_entries=FALSE;
int full_log_entries=FALSE;
int show_scheduled_downtime=TRUE;
int start_second=0;
int start_minute=0;
int start_hour=0;
int start_day=1;
int start_month=1;
int start_year=2000;
int end_second=0;
int end_minute=0;
int end_hour=24;
int end_day=1;
int end_month=1;
int end_year=2000;
int get_date_parts=FALSE;
int select_hostgroups=FALSE;
int select_hosts=FALSE;
int select_servicegroups=FALSE;
int select_services=FALSE;
int select_output_format=FALSE;
int compute_time_from_parts=FALSE;
int show_all_hostgroups=FALSE;
int show_all_hosts=FALSE;
int show_all_servicegroups=FALSE;
int show_all_services=FALSE;
int assume_initial_states=TRUE;
int assume_state_retention=TRUE;
int assume_states_during_notrunning=TRUE;
int initial_assumed_host_state=AS_NO_DATA;
int initial_assumed_service_state=AS_NO_DATA;
int include_soft_states=FALSE;
char *hostgroup_name="";
char *host_name="";
char *servicegroup_name="";
char *svc_description="";
void create_subject_list(void);
void add_subject(int,char *,char *);
avail_subject *find_subject(int,char *,char *);
void compute_availability(void);
void compute_subject_availability(avail_subject *,time_t);
void compute_subject_availability_times(int,int,time_t,time_t,time_t,avail_subject *,archived_state *);
void compute_subject_downtime(avail_subject *,time_t);
void compute_subject_downtime_times(time_t,time_t,avail_subject *,archived_state *);
void compute_subject_downtime_part_times(time_t,time_t,int,avail_subject *);
void display_hostgroup_availability(void);
void display_specific_hostgroup_availability(hostgroup *);
void display_servicegroup_availability(void);
void display_specific_servicegroup_availability(servicegroup *);
void display_host_availability(void);
void display_service_availability(void);
void write_log_entries(avail_subject *);
void get_running_average(double *,double,int);
void host_report_url(char *,char *);
void service_report_url(char *,char *,char *);
void compute_report_times(void);
int convert_host_state_to_archived_state(int);
int convert_service_state_to_archived_state(int);
void add_global_archived_state(int,int,time_t,char *);
void add_archived_state(int,int,time_t,char *,avail_subject *);
void add_scheduled_downtime(int,time_t,avail_subject *);
void free_availability_data(void);
void free_archived_state_list(archived_state *);
void read_archived_state_data(void);
void scan_log_file_for_archived_state_data(char *);
void convert_timeperiod_to_times(int);
unsigned long calculate_total_time(time_t,time_t);
void document_header(int);
void document_footer(void);
int process_cgivars(void);
int backtrack_archives=2;
int earliest_archive=0;
int embedded=FALSE;
int display_header=TRUE;
timeperiod *current_timeperiod=NULL;
int output_format=HTML_OUTPUT;
int main(int argc, char **argv){
int result=OK;
char temp_buffer[MAX_INPUT_BUFFER];
char start_timestring[MAX_DATETIME_LENGTH];
char end_timestring[MAX_DATETIME_LENGTH];
host *temp_host;
service *temp_service;
int is_authorized=TRUE;
time_t report_start_time;
time_t report_end_time;
int days, hours, minutes, seconds;
hostgroup *temp_hostgroup;
servicegroup *temp_servicegroup;
timeperiod *temp_timeperiod;
time_t t3;
time_t current_time;
struct tm *t;
char *firsthostpointer;
/* reset internal CGI variables */
reset_cgi_vars();
/* read the CGI configuration file */
result=read_cgi_config_file(get_cgi_config_location());
if(result==ERROR){
document_header(FALSE);
cgi_config_file_error(get_cgi_config_location());
document_footer();
return ERROR;
}
/* read the main configuration file */
result=read_main_config_file(main_config_file);
if(result==ERROR){
document_header(FALSE);
main_config_file_error(main_config_file);
document_footer();
return ERROR;
}
/* read all object configuration data */
result=read_all_object_configuration_data(main_config_file,READ_ALL_OBJECT_DATA);
if(result==ERROR){
document_header(FALSE);
object_data_error();
document_footer();
return ERROR;
}
/* read all status data */
result=read_all_status_data(get_cgi_config_location(),READ_ALL_STATUS_DATA);
if(result==ERROR){
document_header(FALSE);
status_data_error();
document_footer();
return ERROR;
}
/* initialize time period to last 24 hours */
time(¤t_time);
t2=current_time;
t1=(time_t)(current_time-(60*60*24));
/* default number of backtracked archives */
switch(log_rotation_method){
case LOG_ROTATION_MONTHLY:
backtrack_archives=1;
break;
case LOG_ROTATION_WEEKLY:
backtrack_archives=2;
break;
case LOG_ROTATION_DAILY:
backtrack_archives=4;
break;
case LOG_ROTATION_HOURLY:
backtrack_archives=8;
break;
default:
backtrack_archives=2;
break;
}
/* get the arguments passed in the URL */
process_cgivars();
document_header(TRUE);
/* get authentication information */
get_authentication_information(¤t_authdata);
if(compute_time_from_parts==TRUE)
compute_report_times();
/* make sure times are sane, otherwise swap them */
if(t2current_time){
t2=current_time;
if(t1>t2)
t1=t2-(60*60*24);
}
if(display_header==TRUE){
/* begin top table */
printf("
\n");
if(display_type==DISPLAY_HOST_AVAIL && show_all_hosts==FALSE){
host_report_url("all","View Availability Report For All Hosts");
printf(" \n");
#ifdef USE_TRENDS
printf("View Trends For This Host \n",TRENDS_CGI,url_encode(host_name),t1,t2,(include_soft_states==TRUE)?"yes":"no",(assume_state_retention==TRUE)?"yes":"no",(assume_initial_states==TRUE)?"yes":"no",(assume_states_during_notrunning==TRUE)?"yes":"no",initial_assumed_host_state,backtrack_archives);
#endif
#ifdef USE_HISTOGRAM
printf("View Alert Histogram For This Host \n",HISTOGRAM_CGI,url_encode(host_name),t1,t2,(assume_state_retention==TRUE)?"yes":"no");
#endif
printf("View Status Detail For This Host \n",STATUS_CGI,url_encode(host_name));
printf("View Alert History For This Host \n",HISTORY_CGI,url_encode(host_name));
printf("View Notifications For This Host \n",NOTIFICATIONS_CGI,url_encode(host_name));
}
else if(display_type==DISPLAY_SERVICE_AVAIL && show_all_services==FALSE){
host_report_url(host_name,"View Availability Report For This Host");
printf(" \n");
service_report_url("null","all","View Availability Report For All Services");
printf(" \n");
#ifdef USE_TRENDS
printf("View Trends For This Service \n",url_encode(svc_description),t1,t2,(include_soft_states==TRUE)?"yes":"no",(assume_state_retention==TRUE)?"yes":"no",(assume_initial_states==TRUE)?"yes":"no",(assume_states_during_notrunning==TRUE)?"yes":"no",initial_assumed_service_state,backtrack_archives);
#endif
#ifdef USE_HISTOGRAM
printf("View Alert Histogram For This Service \n",url_encode(svc_description),t1,t2,(assume_state_retention==TRUE)?"yes":"no");
#endif
printf("View Alert History This Service \n",url_encode(svc_description));
printf("View Notifications For This Service \n",url_encode(svc_description));
}
printf("
\n");
}
/* step 3 - ask user for report date range */
if(get_date_parts==TRUE){
time(¤t_time);
t=localtime(¤t_time);
start_day=1;
start_year=t->tm_year+1900;
end_day=t->tm_mday;
end_year=t->tm_year+1900;
printf("
Step 3: Select Report Options
\n");
printf("
\n");
printf("\n");
printf("
\n");
}
/* step 2 - the user wants to select a hostgroup */
else if(select_hostgroups==TRUE){
printf("
Step 2: Select Hostgroup
\n");
printf("
\n");
printf("\n");
printf("
\n");
}
/* step 2 - the user wants to select a host */
else if(select_hosts==TRUE){
printf("
Step 2: Select Host
\n");
printf("
\n");
printf("\n");
printf("
\n");
printf("
Tip: If you want to have the option of getting the availability data in CSV format, select '** ALL HOSTS **' from the pull-down menu.\n");
}
/* step 2 - the user wants to select a servicegroup */
else if(select_servicegroups==TRUE){
printf("
Step 2: Select Servicegroup
\n");
printf("
\n");
printf("\n");
printf("
\n");
}
/* step 2 - the user wants to select a service */
else if(select_services==TRUE){
printf("\n");
printf("
Step 2: Select Service
\n");
printf("
\n");
printf("\n");
printf("
\n");
printf("
Tip: If you want to have the option of getting the availability data in CSV format, select '** ALL SERVICES **' from the pull-down menu.\n");
}
/* generate availability report */
else if(display_type!=DISPLAY_NO_AVAIL){
/* check authorization */
is_authorized=TRUE;
if((display_type==DISPLAY_HOST_AVAIL && show_all_hosts==FALSE) || (display_type==DISPLAY_SERVICE_AVAIL && show_all_services==FALSE)){
if(display_type==DISPLAY_HOST_AVAIL && show_all_hosts==FALSE)
is_authorized=is_authorized_for_host(find_host(host_name),¤t_authdata);
else
is_authorized=is_authorized_for_service(find_service(host_name,svc_description),¤t_authdata);
}
if(is_authorized==FALSE)
printf("
It appears as though you are not authorized to view information for the specified %s...
\n",(display_type==DISPLAY_HOST_AVAIL)?"host":"service");
else{
time(&report_start_time);
/* create list of subjects to collect availability data for */
create_subject_list();
/* read in all necessary archived state data */
read_archived_state_data();
/* compute availability data */
compute_availability();
time(&report_end_time);
if(output_format==HTML_OUTPUT){
get_time_breakdown((time_t)(report_end_time-report_start_time),&days,&hours,&minutes,&seconds);
printf("
[ Availability report completed in %d min %d sec ]
\n",minutes,seconds);
printf("
\n");
}
/* display availability data */
if(display_type==DISPLAY_HOST_AVAIL)
display_host_availability();
else if(display_type==DISPLAY_SERVICE_AVAIL)
display_service_availability();
else if(display_type==DISPLAY_HOSTGROUP_AVAIL)
display_hostgroup_availability();
else if(display_type==DISPLAY_SERVICEGROUP_AVAIL)
display_servicegroup_availability();
/* free memory allocated to availability data */
free_availability_data();
}
}
/* step 1 - ask the user what kind of report they want */
else{
printf("
Step 1: Select Report Type
\n");
printf("
\n");
printf("\n");
printf("
\n");
}
document_footer();
/* free all other allocated memory */
free_memory();
return OK;
}
void document_header(int use_stylesheet){
char date_time[MAX_DATETIME_LENGTH];
time_t current_time;
time_t expire_time;
printf("Cache-Control: no-store\r\n");
printf("Pragma: no-cache\r\n");
time(¤t_time);
get_time_string(¤t_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
printf("Last-Modified: %s\r\n",date_time);
expire_time=(time_t)0;
get_time_string(&expire_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
printf("Expires: %s\r\n",date_time);
if(output_format==HTML_OUTPUT)
printf("Content-type: text/html\r\n\r\n");
else{
printf("Content-type: text/plain\r\n\r\n");
return;
}
if(embedded==TRUE || output_format==CSV_OUTPUT)
return;
printf("\n");
printf("\n");
printf("\n");
printf("Nagios Availability\n");
printf("\n");
if(use_stylesheet==TRUE){
printf("\n",url_stylesheets_path,COMMON_CSS);
printf("\n",url_stylesheets_path,AVAIL_CSS);
}
printf("\n");
printf("\n");
/* include user SSI header */
include_ssi_files(AVAIL_CGI,SSI_HEADER);
return;
}
void document_footer(void){
if(output_format!=HTML_OUTPUT)
return;
if(embedded==TRUE)
return;
/* include user SSI footer */
include_ssi_files(AVAIL_CGI,SSI_FOOTER);
printf("\n");
printf("\n");
return;
}
int process_cgivars(void){
char **variables;
int error=FALSE;
int x;
variables=getcgivars();
for(x=0;variables[x]!=NULL;x++){
/* do some basic length checking on the variable identifier to prevent buffer overflows */
if(strlen(variables[x])>=MAX_INPUT_BUFFER-1){
x++;
continue;
}
/* we found the hostgroup argument */
else if(!strcmp(variables[x],"hostgroup")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
hostgroup_name=(char *)malloc(strlen(variables[x])+1);
if(hostgroup_name==NULL)
hostgroup_name="";
else
strcpy(hostgroup_name,variables[x]);
strip_html_brackets(hostgroup_name);
display_type=DISPLAY_HOSTGROUP_AVAIL;
show_all_hostgroups=(strcmp(hostgroup_name,"all"))?FALSE:TRUE;
}
/* we found the servicegroup argument */
else if(!strcmp(variables[x],"servicegroup")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
servicegroup_name=(char *)malloc(strlen(variables[x])+1);
if(servicegroup_name==NULL)
servicegroup_name="";
else
strcpy(servicegroup_name,variables[x]);
strip_html_brackets(servicegroup_name);
display_type=DISPLAY_SERVICEGROUP_AVAIL;
show_all_servicegroups=(strcmp(servicegroup_name,"all"))?FALSE:TRUE;
}
/* we found the host argument */
else if(!strcmp(variables[x],"host")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
host_name=(char *)malloc(strlen(variables[x])+1);
if(host_name==NULL)
host_name="";
else
strcpy(host_name,variables[x]);
strip_html_brackets(host_name);
display_type=DISPLAY_HOST_AVAIL;
show_all_hosts=(strcmp(host_name,"all"))?FALSE:TRUE;
}
/* we found the service description argument */
else if(!strcmp(variables[x],"service")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
svc_description=(char *)malloc(strlen(variables[x])+1);
if(svc_description==NULL)
svc_description="";
else
strcpy(svc_description,variables[x]);
strip_html_brackets(svc_description);
display_type=DISPLAY_SERVICE_AVAIL;
show_all_services=(strcmp(svc_description,"all"))?FALSE:TRUE;
}
/* we found first time argument */
else if(!strcmp(variables[x],"t1")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
t1=(time_t)strtoul(variables[x],NULL,10);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=FALSE;
}
/* we found first time argument */
else if(!strcmp(variables[x],"t2")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
t2=(time_t)strtoul(variables[x],NULL,10);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=FALSE;
}
/* we found the assume initial states option */
else if(!strcmp(variables[x],"assumeinitialstates")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"yes"))
assume_initial_states=TRUE;
else
assume_initial_states=FALSE;
}
/* we found the assume state during program not running option */
else if(!strcmp(variables[x],"assumestatesduringnotrunning")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"yes"))
assume_states_during_notrunning=TRUE;
else
assume_states_during_notrunning=FALSE;
}
/* we found the initial assumed host state option */
else if(!strcmp(variables[x],"initialassumedhoststate")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
initial_assumed_host_state=atoi(variables[x]);
}
/* we found the initial assumed service state option */
else if(!strcmp(variables[x],"initialassumedservicestate")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
initial_assumed_service_state=atoi(variables[x]);
}
/* we found the assume state retention option */
else if(!strcmp(variables[x],"assumestateretention")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"yes"))
assume_state_retention=TRUE;
else
assume_state_retention=FALSE;
}
/* we found the include soft states option */
else if(!strcmp(variables[x],"includesoftstates")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"yes"))
include_soft_states=TRUE;
else
include_soft_states=FALSE;
}
/* we found the backtrack archives argument */
else if(!strcmp(variables[x],"backtrack")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
backtrack_archives=atoi(variables[x]);
if(backtrack_archives<0)
backtrack_archives=0;
if(backtrack_archives>MAX_ARCHIVE_BACKTRACKS)
backtrack_archives=MAX_ARCHIVE_BACKTRACKS;
#ifdef DEBUG
printf("BACKTRACK ARCHIVES: %d\n",backtrack_archives);
#endif
}
/* we found the standard timeperiod argument */
else if(!strcmp(variables[x],"timeperiod")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"today"))
timeperiod_type=TIMEPERIOD_TODAY;
else if(!strcmp(variables[x],"yesterday"))
timeperiod_type=TIMEPERIOD_YESTERDAY;
else if(!strcmp(variables[x],"thisweek"))
timeperiod_type=TIMEPERIOD_THISWEEK;
else if(!strcmp(variables[x],"lastweek"))
timeperiod_type=TIMEPERIOD_LASTWEEK;
else if(!strcmp(variables[x],"thismonth"))
timeperiod_type=TIMEPERIOD_THISMONTH;
else if(!strcmp(variables[x],"lastmonth"))
timeperiod_type=TIMEPERIOD_LASTMONTH;
else if(!strcmp(variables[x],"thisquarter"))
timeperiod_type=TIMEPERIOD_THISQUARTER;
else if(!strcmp(variables[x],"lastquarter"))
timeperiod_type=TIMEPERIOD_LASTQUARTER;
else if(!strcmp(variables[x],"thisyear"))
timeperiod_type=TIMEPERIOD_THISYEAR;
else if(!strcmp(variables[x],"lastyear"))
timeperiod_type=TIMEPERIOD_LASTYEAR;
else if(!strcmp(variables[x],"last24hours"))
timeperiod_type=TIMEPERIOD_LAST24HOURS;
else if(!strcmp(variables[x],"last7days"))
timeperiod_type=TIMEPERIOD_LAST7DAYS;
else if(!strcmp(variables[x],"last31days"))
timeperiod_type=TIMEPERIOD_LAST31DAYS;
else if(!strcmp(variables[x],"custom"))
timeperiod_type=TIMEPERIOD_CUSTOM;
else
continue;
convert_timeperiod_to_times(timeperiod_type);
compute_time_from_parts=FALSE;
}
/* we found the embed option */
else if(!strcmp(variables[x],"embedded"))
embedded=TRUE;
/* we found the noheader option */
else if(!strcmp(variables[x],"noheader"))
display_header=FALSE;
/* we found the CSV output option */
else if(!strcmp(variables[x],"csvoutput")){
display_header=FALSE;
output_format=CSV_OUTPUT;
}
/* we found the log entries option */
else if(!strcmp(variables[x],"show_log_entries"))
show_log_entries=TRUE;
/* we found the full log entries option */
else if(!strcmp(variables[x],"full_log_entries"))
full_log_entries=TRUE;
/* we found the get date parts option */
else if(!strcmp(variables[x],"get_date_parts"))
get_date_parts=TRUE;
/* we found the report type selection option */
else if(!strcmp(variables[x],"report_type")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"hostgroups"))
select_hostgroups=TRUE;
else if(!strcmp(variables[x],"servicegroups"))
select_servicegroups=TRUE;
else if(!strcmp(variables[x],"hosts"))
select_hosts=TRUE;
else
select_services=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"smon")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
start_month=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"sday")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
start_day=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"syear")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
start_year=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"smin")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
start_minute=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"ssec")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
start_second=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"shour")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
start_hour=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"emon")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
end_month=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"eday")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
end_day=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"eyear")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
end_year=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"emin")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
end_minute=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"esec")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
end_second=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found time argument */
else if(!strcmp(variables[x],"ehour")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(timeperiod_type!=TIMEPERIOD_CUSTOM)
continue;
end_hour=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
/* we found the show scheduled downtime option */
else if(!strcmp(variables[x],"showscheduleddowntime")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"yes"))
show_scheduled_downtime=TRUE;
else
show_scheduled_downtime=FALSE;
}
/* we found the report timeperiod option */
else if(!strcmp(variables[x],"rpttimeperiod")){
timeperiod *temp_timeperiod;
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
for(temp_timeperiod=timeperiod_list;temp_timeperiod!=NULL;temp_timeperiod=temp_timeperiod->next){
if(!strcmp(url_encode(temp_timeperiod->name),variables[x])){
current_timeperiod=temp_timeperiod;
break;
}
}
}
}
/* free memory allocated to the CGI variables */
free_cgivars(variables);
return error;
}
/* computes availability data for all subjects */
void compute_availability(void){
avail_subject *temp_subject;
time_t current_time;
time(¤t_time);
for(temp_subject=subject_list;temp_subject!=NULL;temp_subject=temp_subject->next){
compute_subject_availability(temp_subject,current_time);
compute_subject_downtime(temp_subject,current_time);
}
return;
}
/* computes availability data for a given subject */
void compute_subject_availability(avail_subject *subject, time_t current_time){
archived_state *temp_as;
archived_state *last_as;
time_t a;
time_t b;
int current_state=AS_NO_DATA;
int have_some_real_data=FALSE;
hoststatus *hststatus=NULL;
servicestatus *svcstatus=NULL;
int first_real_state=AS_NO_DATA;
time_t initial_assumed_time;
int initial_assumed_state=AS_NO_DATA;
int error;
/* if left hand of graph is after current time, we can't do anything at all.... */
if(t1>current_time)
return;
/* get current state of host or service if possible */
if(subject->type==HOST_SUBJECT)
hststatus=find_hoststatus(subject->host_name);
else
svcstatus=find_servicestatus(subject->host_name,subject->service_description);
/************************************/
/* INSERT CURRENT STATE (IF WE CAN) */
/************************************/
/* if current time DOES NOT fall within graph bounds, so we can't do anything as far as assuming current state */
/* if we don't have any data, assume current state (if possible) */
if(subject->as_list==NULL && current_time>t1 && current_time<=t2){
/* we don't have any historical information, but the current time falls within the reporting period, so use */
/* the current status of the host/service as the starting data */
if(subject->type==HOST_SUBJECT){
if(hststatus!=NULL){
if(hststatus->status==HOST_DOWN)
subject->last_known_state=AS_HOST_DOWN;
else if(hststatus->status==HOST_UNREACHABLE)
subject->last_known_state=AS_HOST_UNREACHABLE;
else if(hststatus->status==HOST_UP)
subject->last_known_state=AS_HOST_UP;
else
subject->last_known_state=AS_NO_DATA;
if(subject->last_known_state!=AS_NO_DATA){
/* add a dummy archived state item, so something can get graphed */
add_archived_state(subject->last_known_state,AS_HARD_STATE,t1,"Current Host State Assumed (Faked Log Entry)",subject);
/* use the current state as the last known real state */
first_real_state=subject->last_known_state;
}
}
}
else{
if(svcstatus!=NULL){
if(svcstatus->status==SERVICE_OK)
subject->last_known_state=AS_SVC_OK;
else if(svcstatus->status==SERVICE_WARNING)
subject->last_known_state=AS_SVC_WARNING;
else if(svcstatus->status==SERVICE_CRITICAL)
subject->last_known_state=AS_SVC_CRITICAL;
else if(svcstatus->status==SERVICE_UNKNOWN)
subject->last_known_state=AS_SVC_UNKNOWN;
else
subject->last_known_state=AS_NO_DATA;
if(subject->last_known_state!=AS_NO_DATA){
/* add a dummy archived state item, so something can get graphed */
add_archived_state(subject->last_known_state,AS_HARD_STATE,t1,"Current Service State Assumed (Faked Log Entry)",subject);
/* use the current state as the last known real state */
first_real_state=subject->last_known_state;
}
}
}
}
/******************************************/
/* INSERT FIRST ASSUMED STATE (IF WE CAN) */
/******************************************/
if((subject->type==HOST_SUBJECT && initial_assumed_host_state!=AS_NO_DATA) || (subject->type==SERVICE_SUBJECT && initial_assumed_service_state!=AS_NO_DATA)){
/* see if its okay to assume initial state for this subject */
error=FALSE;
if(subject->type==SERVICE_SUBJECT){
if(initial_assumed_service_state!=AS_SVC_OK && initial_assumed_service_state!=AS_SVC_WARNING && initial_assumed_service_state!=AS_SVC_UNKNOWN && initial_assumed_service_state!=AS_SVC_CRITICAL && initial_assumed_service_state!=AS_CURRENT_STATE)
error=TRUE;
else
initial_assumed_state=initial_assumed_service_state;
if(initial_assumed_service_state==AS_CURRENT_STATE && svcstatus==NULL)
error=TRUE;
}
else{
if(initial_assumed_host_state!=AS_HOST_UP && initial_assumed_host_state!=AS_HOST_DOWN && initial_assumed_host_state!=AS_HOST_UNREACHABLE && initial_assumed_host_state!=AS_CURRENT_STATE)
error=TRUE;
else
initial_assumed_state=initial_assumed_host_state;
if(initial_assumed_host_state==AS_CURRENT_STATE && hststatus==NULL)
error=TRUE;
}
/* get the current state if applicable */
if(((subject->type==HOST_SUBJECT && initial_assumed_host_state==AS_CURRENT_STATE) || (subject->type==SERVICE_SUBJECT && initial_assumed_service_state==AS_CURRENT_STATE)) && error==FALSE){
if(subject->type==SERVICE_SUBJECT){
switch(svcstatus->status){
case SERVICE_OK:
initial_assumed_state=AS_SVC_OK;
break;
case SERVICE_WARNING:
initial_assumed_state=AS_SVC_WARNING;
break;
case SERVICE_UNKNOWN:
initial_assumed_state=AS_SVC_UNKNOWN;
break;
case SERVICE_CRITICAL:
initial_assumed_state=AS_SVC_CRITICAL;
break;
default:
error=TRUE;
break;
}
}
else{
switch(hststatus->status){
case HOST_DOWN:
initial_assumed_state=AS_HOST_DOWN;
break;
case HOST_UNREACHABLE:
initial_assumed_state=AS_HOST_UNREACHABLE;
break;
case HOST_UP:
initial_assumed_state=AS_HOST_UP;
break;
default:
error=TRUE;
break;
}
}
}
if(error==FALSE){
/* add this assumed state entry before any entries in the list and <= t1 */
if(subject->as_list==NULL)
initial_assumed_time=t1;
else if(subject->as_list->time_stamp>t1)
initial_assumed_time=t1;
else
initial_assumed_time=subject->as_list->time_stamp-1;
if(subject->type==HOST_SUBJECT)
add_archived_state(initial_assumed_state,AS_HARD_STATE,initial_assumed_time,"First Host State Assumed (Faked Log Entry)",subject);
else
add_archived_state(initial_assumed_state,AS_HARD_STATE,initial_assumed_time,"First Service State Assumed (Faked Log Entry)",subject);
}
}
/**************************************/
/* BAIL OUT IF WE DON'T HAVE ANYTHING */
/**************************************/
have_some_real_data=FALSE;
for(temp_as=subject->as_list;temp_as!=NULL;temp_as=temp_as->next){
if(temp_as->entry_type!=AS_NO_DATA && temp_as->entry_type!=AS_PROGRAM_START && temp_as->entry_type!=AS_PROGRAM_END){
have_some_real_data=TRUE;
break;
}
}
if(have_some_real_data==FALSE)
return;
last_as=NULL;
subject->earliest_time=t2;
subject->latest_time=t1;
#ifdef DEBUG
printf("--- BEGINNING/MIDDLE SECTION --- \n");
#endif
/**********************************/
/* BEGINNING/MIDDLE SECTION */
/**********************************/
for(temp_as=subject->as_list;temp_as!=NULL;temp_as=temp_as->next){
/* keep this as last known state if this is the first entry or if it occurs before the starting point of the graph */
if((temp_as->time_stamp<=t1 || temp_as==subject->as_list) && (temp_as->entry_type!=AS_NO_DATA && temp_as->entry_type!=AS_PROGRAM_END && temp_as->entry_type!=AS_PROGRAM_START)){
subject->last_known_state=temp_as->entry_type;
#ifdef DEBUG
printf("SETTING LAST KNOWN STATE=%d \n",subject->last_known_state);
#endif
}
/* skip this entry if it occurs before the starting point of the graph */
if(temp_as->time_stamp<=t1){
#ifdef DEBUG
printf("SKIPPING PRE-EVENT: %d @ %lu \n",temp_as->entry_type,temp_as->time_stamp);
#endif
last_as=temp_as;
continue;
}
/* graph this span if we're not on the first item */
if(last_as!=NULL){
a=last_as->time_stamp;
b=temp_as->time_stamp;
/* we've already passed the last time displayed in the graph */
if(a>t2)
break;
/* only graph this data if its on the graph */
else if(b>t1){
/* clip last time if it exceeds graph limits */
if(b>t2)
b=t2;
/* clip first time if it precedes graph limits */
if(aearliest_time){
subject->earliest_time=a;
subject->earliest_state=last_as->entry_type;
}
/* save this time if its the latest we've graphed */
if(b>subject->latest_time){
subject->latest_time=b;
subject->latest_state=last_as->entry_type;
}
/* compute availability times for this chunk */
compute_subject_availability_times(last_as->entry_type,temp_as->entry_type,last_as->time_stamp,a,b,subject,temp_as);
/* return if we've reached the end of the graph limits */
if(b>=t2){
last_as=temp_as;
break;
}
}
}
/* keep track of the last item */
last_as=temp_as;
}
#ifdef DEBUG
printf("--- END SECTION --- \n");
#endif
/**********************************/
/* END SECTION */
/**********************************/
if(last_as!=NULL){
/* don't process an entry that is beyond the limits of the graph */
if(last_as->time_stampt2)
b=t2;
a=last_as->time_stamp;
if(atype==HOST_SUBJECT)
current_state=AS_HOST_UP;
else
current_state=AS_SVC_OK;
/* compute availability times for last state */
compute_subject_availability_times(last_as->entry_type,current_state,last_as->time_stamp,a,b,subject,last_as);
}
}
return;
}
/* computes availability times */
void compute_subject_availability_times(int first_state,int last_state,time_t real_start_time,time_t start_time,time_t end_time,avail_subject *subject, archived_state *as){
int start_state;
int end_state;
unsigned long state_duration;
struct tm *t;
unsigned long midnight_today;
int weekday;
timerange *temp_timerange;
unsigned long temp_duration;
unsigned long temp_end;
unsigned long temp_start;
unsigned long start;
unsigned long end;
#ifdef DEBUG
if(subject->type==HOST_SUBJECT)
printf("HOST '%s'...\n",subject->host_name);
else
printf("SERVICE '%s' ON HOST '%s'...\n",subject->service_description,subject->host_name);
printf("COMPUTING %d->%d FROM %lu to %lu (%lu seconds) FOR %s \n",first_state,last_state,start_time,end_time,(end_time-start_time),(subject->type==HOST_SUBJECT)?"HOST":"SERVICE");
#endif
/* clip times if necessary */
if(start_timet2)
end_time=t2;
/* make sure this is a valid time */
if(start_time>t2)
return;
if(end_timetm_sec=0;
t->tm_min=0;
t->tm_hour=0;
midnight_today=(unsigned long)mktime(t);
weekday=t->tm_wday;
while(midnight_todaymidnight_today)
temp_start=start_time-midnight_today;
#ifdef DEBUG
printf("Matching: %ld -> %ld. (%ld -> %ld) \n",temp_start, temp_end, midnight_today+temp_start, midnight_today+temp_end);
#endif
/* check all time ranges for this day of the week */
for(temp_timerange=current_timeperiod->days[weekday];temp_timerange!=NULL;temp_timerange=temp_timerange->next){
#ifdef DEBUG
printf("
Ignored time: %ld -> %ld \n",start, end);
#endif
}
state_duration+=temp_duration;
temp_start=0;
midnight_today+=86400;
if(++weekday>6)
weekday=0;
}
}
/* no report timeperiod was selected (assume 24x7) */
else{
/* calculate time in this state */
state_duration=(unsigned long)(end_time-start_time);
}
/* can't graph if we don't have data... */
if(first_state==AS_NO_DATA || last_state==AS_NO_DATA){
subject->time_indeterminate_nodata+=state_duration;
return;
}
if(first_state==AS_PROGRAM_START && (last_state==AS_PROGRAM_END || last_state==AS_PROGRAM_START)){
if(assume_initial_states==FALSE){
subject->time_indeterminate_nodata+=state_duration;
return;
}
}
if(first_state==AS_PROGRAM_END){
/* added 7/24/03 */
if(assume_states_during_notrunning==TRUE){
first_state=subject->last_known_state;
}
else{
subject->time_indeterminate_notrunning+=state_duration;
return;
}
}
/* special case if first entry was program start */
if(first_state==AS_PROGRAM_START){
if(assume_initial_states==TRUE){
if(assume_state_retention==TRUE)
start_state=subject->last_known_state;
else{
if(subject->type==HOST_SUBJECT)
start_state=AS_HOST_UP;
else
start_state=AS_SVC_OK;
}
}
else
return;
}
else{
start_state=first_state;
subject->last_known_state=first_state;
}
/* special case if last entry was program stop */
if(last_state==AS_PROGRAM_END)
end_state=first_state;
else
end_state=last_state;
/* save "processed state" info */
as->processed_state=start_state;
#ifdef DEBUG
printf("PASSED TIME CHECKS, CLIPPED VALUES: START=%lu, END=%lu\n",start_time,end_time);
#endif
/* add time in this state to running totals */
switch(start_state){
case AS_HOST_UP:
subject->time_up+=state_duration;
break;
case AS_HOST_DOWN:
subject->time_down+=state_duration;
break;
case AS_HOST_UNREACHABLE:
subject->time_unreachable+=state_duration;
break;
case AS_SVC_OK:
subject->time_ok+=state_duration;
break;
case AS_SVC_WARNING:
subject->time_warning+=state_duration;
break;
case AS_SVC_UNKNOWN:
subject->time_unknown+=state_duration;
break;
case AS_SVC_CRITICAL:
subject->time_critical+=state_duration;
break;
default:
break;
}
return;
}
/* computes downtime data for a given subject */
void compute_subject_downtime(avail_subject *subject, time_t current_time){
archived_state *temp_sd;
time_t start_time;
time_t end_time;
int host_downtime_depth=0;
int service_downtime_depth=0;
int process_chunk=FALSE;
#ifdef DEBUG2
printf("COMPUTE_SUBJECT_DOWNTIME\n");
#endif
/* if left hand of graph is after current time, we can't do anything at all.... */
if(t1>current_time)
return;
/* no scheduled downtime data for subject... */
if(subject->sd_list==NULL)
return;
/* all data we have occurs after last time on graph... */
if(subject->sd_list->time_stamp>=t2)
return;
/* initialize pointer */
temp_sd=subject->sd_list;
/* special case if first entry is the end of scheduled downtime */
if((temp_sd->entry_type==AS_HOST_DOWNTIME_END || temp_sd->entry_type==AS_SVC_DOWNTIME_END) && temp_sd->time_stamp>t1){
#ifdef DEBUG2
printf("\tSPECIAL DOWNTIME CASE\n");
#endif
start_time=t1;
end_time=(temp_sd->time_stamp>t2)?t2:temp_sd->time_stamp;
compute_subject_downtime_times(start_time,end_time,subject,NULL);
temp_sd=temp_sd->next;
}
/* process all periods of scheduled downtime */
for(;temp_sd!=NULL;temp_sd=temp_sd->next){
/* we've passed graph bounds... */
if(temp_sd->time_stamp>=t2)
break;
if(temp_sd->entry_type==AS_HOST_DOWNTIME_START)
host_downtime_depth++;
else if(temp_sd->entry_type==AS_HOST_DOWNTIME_END)
host_downtime_depth--;
else if(temp_sd->entry_type==AS_SVC_DOWNTIME_START)
service_downtime_depth++;
else if(temp_sd->entry_type==AS_SVC_DOWNTIME_END)
service_downtime_depth--;
else
continue;
process_chunk=FALSE;
if(temp_sd->entry_type==AS_HOST_DOWNTIME_START || temp_sd->entry_type==AS_SVC_DOWNTIME_START)
process_chunk=TRUE;
else if(subject->type==SERVICE_SUBJECT && (host_downtime_depth>0 || service_downtime_depth>0))
process_chunk=TRUE;
/* process this specific "chunk" of scheduled downtime */
if(process_chunk==TRUE){
start_time=temp_sd->time_stamp;
end_time=(temp_sd->next==NULL)?current_time:temp_sd->next->time_stamp;
/* check time sanity */
if(end_time<=t1)
continue;
if(start_time>=t2)
continue;
if(start_time>=end_time)
continue;
/* clip time values */
if(start_timet2)
end_time=t2;
compute_subject_downtime_times(start_time,end_time,subject,temp_sd);
}
}
return;
}
/* computes downtime times */
void compute_subject_downtime_times(time_t start_time, time_t end_time, avail_subject *subject, archived_state *sd){
archived_state *temp_as=NULL;
time_t part_start_time=0L;
time_t part_subject_state=0L;
int save_status=0;
int saved_status=0;
int saved_stamp=0;
int calc_temp=0;
int count=0;
archived_state *temp_before=NULL;
archived_state *last=NULL;
#ifdef DEBUG2
printf("
",start_time,end_time,t1,t2);
#endif
/* times are weird, so bail out... */
if(start_time>end_time)
return;
if(start_timet2)
return;
/* find starting point in archived state list */
if(sd==NULL){
#ifdef DEBUG2
printf("
",(sd==NULL)?"NULL":"Not NULL");
#endif
/* temp_as now points to first event to possibly "break" this chunk */
for(;temp_as!=NULL;temp_as=temp_as->next){
count++;
last=temp_as;
if(temp_before==NULL){
if(last->time_stamp>start_time){
if(last->time_stamp>end_time)
compute_subject_downtime_part_times(start_time,end_time,part_subject_state,subject);
else
compute_subject_downtime_part_times(start_time,last->time_stamp,part_subject_state,subject);
}
temp_before=temp_as;
saved_status=temp_as->entry_type;
saved_stamp=temp_as->time_stamp;
/* check if first time is before schedule downtime */
if(saved_stampentry_type){
/* is outside schedule time, use end schdule downtime */
if(temp_as->time_stamp>end_time){
if(saved_stamptime_stamp,saved_status,subject);
else
compute_subject_downtime_part_times(saved_stamp,temp_as->time_stamp,saved_status,subject);
}
saved_status=temp_as->entry_type;
saved_stamp=temp_as->time_stamp;
}
}
/* just one entry inside the scheduled downtime */
if(count==0)
compute_subject_downtime_part_times(start_time,end_time,part_subject_state,subject);
else{
/* is outside scheduled time, use end schdule downtime */
if(last->time_stamp>end_time)
compute_subject_downtime_part_times(saved_stamp,end_time,saved_status,subject);
else
compute_subject_downtime_part_times(saved_stamp,last->time_stamp,saved_status,subject);
}
return;
}
/* computes downtime times */
void compute_subject_downtime_part_times(time_t start_time, time_t end_time, int subject_state, avail_subject *subject){
unsigned long state_duration;
#ifdef DEBUG2
printf("ENTERING COMPUTE_SUBJECT_DOWNTIME_PART_TIMES\n");
#endif
/* times are weird */
if(start_time>end_time)
return;
state_duration=(unsigned long)(end_time-start_time);
switch(subject_state){
case AS_HOST_UP:
subject->scheduled_time_up+=state_duration;
break;
case AS_HOST_DOWN:
subject->scheduled_time_down+=state_duration;
break;
case AS_HOST_UNREACHABLE:
subject->scheduled_time_unreachable+=state_duration;
break;
case AS_SVC_OK:
subject->scheduled_time_ok+=state_duration;
break;
case AS_SVC_WARNING:
subject->scheduled_time_warning+=state_duration;
break;
case AS_SVC_UNKNOWN:
subject->scheduled_time_unknown+=state_duration;
break;
case AS_SVC_CRITICAL:
subject->scheduled_time_critical+=state_duration;
break;
default:
subject->scheduled_time_indeterminate+=state_duration;
break;
}
#ifdef DEBUG2
printf("\tSUBJECT DOWNTIME: Host '%s', Service '%s', State=%d, Duration=%lu, Start=%lu\n",subject->host_name,(subject->service_description==NULL)?"NULL":subject->service_description,subject_state,state_duration,start_time);
#endif
return;
}
/* convert current host state to archived state value */
int convert_host_state_to_archived_state(int current_status){
if(current_status==HOST_UP)
return AS_HOST_UP;
if(current_status==HOST_DOWN)
return AS_HOST_DOWN;
if(current_status==HOST_UNREACHABLE)
return AS_HOST_UNREACHABLE;
return AS_NO_DATA;
}
/* convert current service state to archived state value */
int convert_service_state_to_archived_state(int current_status){
if(current_status==SERVICE_OK)
return AS_SVC_OK;
if(current_status==SERVICE_UNKNOWN)
return AS_SVC_UNKNOWN;
if(current_status==SERVICE_WARNING)
return AS_SVC_WARNING;
if(current_status==SERVICE_CRITICAL)
return AS_SVC_CRITICAL;
return AS_NO_DATA;
}
/* create list of subjects to collect availability data for */
void create_subject_list(void){
hostgroup *temp_hostgroup;
hostgroupmember *temp_hgmember;
servicegroup *temp_servicegroup;
servicegroupmember *temp_sgmember;
host *temp_host;
service *temp_service;
char *last_host_name="";
/* we're displaying one or more hosts */
if(display_type==DISPLAY_HOST_AVAIL && host_name!=""){
/* we're only displaying a specific host (and summaries for all services associated with it) */
if(show_all_hosts==FALSE){
add_subject(HOST_SUBJECT,host_name,NULL);
for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
if(!strcmp(temp_service->host_name,host_name))
add_subject(SERVICE_SUBJECT,host_name,temp_service->description);
}
}
/* we're displaying all hosts */
else{
for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next)
add_subject(HOST_SUBJECT,temp_host->name,NULL);
}
}
/* we're displaying a specific service */
else if(display_type==DISPLAY_SERVICE_AVAIL && svc_description!=""){
/* we're only displaying a specific service */
if(show_all_services==FALSE)
add_subject(SERVICE_SUBJECT,host_name,svc_description);
/* we're displaying all services */
else{
for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next)
add_subject(SERVICE_SUBJECT,temp_service->host_name,temp_service->description);
}
}
/* we're displaying one or more hostgroups (the host members of the groups) */
else if(display_type==DISPLAY_HOSTGROUP_AVAIL && hostgroup_name!=""){
/* we're displaying all hostgroups */
if(show_all_hostgroups==TRUE){
for(temp_hostgroup=hostgroup_list;temp_hostgroup!=NULL;temp_hostgroup=temp_hostgroup->next){
for(temp_hgmember=temp_hostgroup->members;temp_hgmember!=NULL;temp_hgmember=temp_hgmember->next)
add_subject(HOST_SUBJECT,temp_hgmember->host_name,NULL);
}
}
/* we're only displaying a specific hostgroup */
else{
temp_hostgroup=find_hostgroup(hostgroup_name);
if(temp_hostgroup!=NULL){
for(temp_hgmember=temp_hostgroup->members;temp_hgmember!=NULL;temp_hgmember=temp_hgmember->next)
add_subject(HOST_SUBJECT,temp_hgmember->host_name,NULL);
}
}
}
/* we're displaying one or more servicegroups (the host and service members of the groups) */
else if(display_type==DISPLAY_SERVICEGROUP_AVAIL && servicegroup_name!=""){
/* we're displaying all servicegroups */
if(show_all_servicegroups==TRUE){
for(temp_servicegroup=servicegroup_list;temp_servicegroup!=NULL;temp_servicegroup=temp_servicegroup->next){
for(temp_sgmember=temp_servicegroup->members;temp_sgmember!=NULL;temp_sgmember=temp_sgmember->next){
add_subject(SERVICE_SUBJECT,temp_sgmember->host_name,temp_sgmember->service_description);
if(strcmp(last_host_name,temp_sgmember->host_name))
add_subject(HOST_SUBJECT,temp_sgmember->host_name,NULL);
last_host_name=temp_sgmember->host_name;
}
}
}
/* we're only displaying a specific servicegroup */
else{
temp_servicegroup=find_servicegroup(servicegroup_name);
if(temp_servicegroup!=NULL){
for(temp_sgmember=temp_servicegroup->members;temp_sgmember!=NULL;temp_sgmember=temp_sgmember->next){
add_subject(SERVICE_SUBJECT,temp_sgmember->host_name,temp_sgmember->service_description);
if(strcmp(last_host_name,temp_sgmember->host_name))
add_subject(HOST_SUBJECT,temp_sgmember->host_name,NULL);
last_host_name=temp_sgmember->host_name;
}
}
}
}
return;
}
/* adds a subject */
void add_subject(int subject_type, char *hn, char *sd){
avail_subject *last_subject=NULL;
avail_subject *temp_subject=NULL;
avail_subject *new_subject=NULL;
int is_authorized=FALSE;
/* bail if we've already added the subject */
if(find_subject(subject_type,hn,sd))
return;
/* see if the user is authorized to see data for this host or service */
if(subject_type==HOST_SUBJECT)
is_authorized=is_authorized_for_host(find_host(hn),¤t_authdata);
else
is_authorized=is_authorized_for_service(find_service(hn,sd),¤t_authdata);
if(is_authorized==FALSE)
return;
/* allocate memory for the new entry */
new_subject=(avail_subject *)malloc(sizeof(avail_subject));
if(new_subject==NULL)
return;
/* allocate memory for the host name */
if(hn!=NULL){
new_subject->host_name=(char *)malloc(strlen(hn)+1);
if(new_subject->host_name!=NULL)
strcpy(new_subject->host_name,hn);
}
else
new_subject->host_name=NULL;
/* allocate memory for the service description */
if(sd!=NULL){
new_subject->service_description=(char *)malloc(strlen(sd)+1);
if(new_subject->service_description!=NULL)
strcpy(new_subject->service_description,sd);
}
else
new_subject->service_description=NULL;
new_subject->type=subject_type;
new_subject->earliest_state=AS_NO_DATA;
new_subject->latest_state=AS_NO_DATA;
new_subject->time_up=0L;
new_subject->time_down=0L;
new_subject->time_unreachable=0L;
new_subject->time_ok=0L;
new_subject->time_warning=0L;
new_subject->time_unknown=0L;
new_subject->time_critical=0L;
new_subject->scheduled_time_up=0L;
new_subject->scheduled_time_down=0L;
new_subject->scheduled_time_unreachable=0L;
new_subject->scheduled_time_ok=0L;
new_subject->scheduled_time_warning=0L;
new_subject->scheduled_time_unknown=0L;
new_subject->scheduled_time_critical=0L;
new_subject->scheduled_time_indeterminate=0L;
new_subject->time_indeterminate_nodata=0L;
new_subject->time_indeterminate_notrunning=0L;
new_subject->as_list=NULL;
new_subject->as_list_tail=NULL;
new_subject->sd_list=NULL;
new_subject->last_known_state=AS_NO_DATA;
/* add the new entry to the list in memory, sorted by host name */
last_subject=subject_list;
for(temp_subject=subject_list;temp_subject!=NULL;temp_subject=temp_subject->next){
if(strcmp(new_subject->host_name,temp_subject->host_name)<0){
new_subject->next=temp_subject;
if(temp_subject==subject_list)
subject_list=new_subject;
else
last_subject->next=new_subject;
break;
}
else
last_subject=temp_subject;
}
if(subject_list==NULL){
new_subject->next=NULL;
subject_list=new_subject;
}
else if(temp_subject==NULL){
new_subject->next=NULL;
last_subject->next=new_subject;
}
return;
}
/* finds a specific subject */
avail_subject *find_subject(int type, char *hn, char *sd){
avail_subject *temp_subject;
if(hn==NULL)
return NULL;
if(type==SERVICE_SUBJECT && sd==NULL)
return NULL;
for(temp_subject=subject_list;temp_subject!=NULL;temp_subject=temp_subject->next){
if(temp_subject->type!=type)
continue;
if(strcmp(hn,temp_subject->host_name))
continue;
if(type==SERVICE_SUBJECT && strcmp(sd,temp_subject->service_description))
continue;
return temp_subject;
}
return NULL;
}
/* adds an archived state entry to all subjects */
void add_global_archived_state(int entry_type, int state_type, time_t time_stamp, char *state_info){
avail_subject *temp_subject;
for(temp_subject=subject_list;temp_subject!=NULL;temp_subject=temp_subject->next)
add_archived_state(entry_type,state_type,time_stamp,state_info,temp_subject);
return;
}
/* adds an archived state entry to a specific subject */
void add_archived_state(int entry_type, int state_type, time_t time_stamp, char *state_info, avail_subject *subject){
archived_state *last_as=NULL;
archived_state *temp_as=NULL;
archived_state *new_as=NULL;
/* allocate memory for the new entry */
new_as=(archived_state *)malloc(sizeof(archived_state));
if(new_as==NULL)
return;
/* allocate memory for the state info */
if(state_info!=NULL){
new_as->state_info=(char *)malloc(strlen(state_info)+1);
if(new_as->state_info!=NULL)
strcpy(new_as->state_info,state_info);
}
else new_as->state_info=NULL;
/* initialize the "processed state" value - this gets modified later for most entries */
if(entry_type!=AS_PROGRAM_START && entry_type!=AS_PROGRAM_END && entry_type!=AS_NO_DATA)
new_as->processed_state=entry_type;
else
new_as->processed_state=AS_NO_DATA;
new_as->entry_type=entry_type;
new_as->state_type=state_type;
new_as->time_stamp=time_stamp;
new_as->misc_ptr=NULL;
/* add the new entry to the list in memory, sorted by time (more recent entries should appear towards end of list) */
last_as=subject->as_list;
for(temp_as=subject->as_list;temp_as!=NULL;temp_as=temp_as->next){
if(new_as->time_stamptime_stamp){
new_as->next=temp_as;
if(temp_as==subject->as_list)
subject->as_list=new_as;
else
last_as->next=new_as;
break;
}
else
last_as=temp_as;
}
if(subject->as_list==NULL){
new_as->next=NULL;
subject->as_list=new_as;
}
else if(temp_as==NULL){
new_as->next=NULL;
last_as->next=new_as;
}
/* update "tail" of the list - not really the tail, just last item added */
subject->as_list_tail=new_as;
return;
}
/* adds a scheduled downtime entry to a specific subject */
void add_scheduled_downtime(int state_type, time_t time_stamp, avail_subject *subject){
archived_state *last_sd=NULL;
archived_state *temp_sd=NULL;
archived_state *new_sd=NULL;
/* allocate memory for the new entry */
new_sd=(archived_state *)malloc(sizeof(archived_state));
if(new_sd==NULL)
return;
new_sd->state_info=NULL;
new_sd->processed_state=state_type;
new_sd->entry_type=state_type;
new_sd->time_stamp=time_stamp;
new_sd->misc_ptr=subject->as_list_tail;
/* add the new entry to the list in memory, sorted by time (more recent entries should appear towards end of list) */
last_sd=subject->sd_list;
for(temp_sd=subject->sd_list;temp_sd!=NULL;temp_sd=temp_sd->next){
if(new_sd->time_stamp<=temp_sd->time_stamp){
new_sd->next=temp_sd;
if(temp_sd==subject->sd_list)
subject->sd_list=new_sd;
else
last_sd->next=new_sd;
break;
}
else
last_sd=temp_sd;
}
if(subject->sd_list==NULL){
new_sd->next=NULL;
subject->sd_list=new_sd;
}
else if(temp_sd==NULL){
new_sd->next=NULL;
last_sd->next=new_sd;
}
return;
}
/* frees memory allocated to all availability data */
void free_availability_data(void){
avail_subject *this_subject;
avail_subject *next_subject;
for(this_subject=subject_list;this_subject!=NULL;){
next_subject=this_subject->next;
if(this_subject->host_name!=NULL)
free(this_subject->host_name);
if(this_subject->service_description!=NULL)
free(this_subject->service_description);
free_archived_state_list(this_subject->as_list);
free_archived_state_list(this_subject->sd_list);
free(this_subject);
this_subject=next_subject;
}
return;
}
/* frees memory allocated to the archived state list */
void free_archived_state_list(archived_state *as_list){
archived_state *this_as=NULL;
archived_state *next_as=NULL;
for(this_as=as_list;this_as!=NULL;){
next_as=this_as->next;
if(this_as->state_info!=NULL)
free(this_as->state_info);
free(this_as);
this_as=next_as;
}
as_list=NULL;
return;
}
/* reads log files for archived state data */
void read_archived_state_data(void){
char filename[MAX_FILENAME_LENGTH];
int oldest_archive=0;
int newest_archive=0;
int current_archive=0;
/* determine oldest archive to use when scanning for data (include backtracked archives as well) */
oldest_archive=determine_archive_to_use_from_time(t1);
if(log_rotation_method!=LOG_ROTATION_NONE)
oldest_archive+=backtrack_archives;
/* determine most recent archive to use when scanning for data */
newest_archive=determine_archive_to_use_from_time(t2);
if(oldest_archivenext){
if(temp_subject->type!=SERVICE_SUBJECT)
continue;
if(strcmp(temp_subject->host_name,entry_host_name))
continue;
if(show_scheduled_downtime==FALSE)
continue;
if(strstr(input,";STARTED;"))
add_scheduled_downtime(AS_HOST_DOWNTIME_START,time_stamp,temp_subject);
else
add_scheduled_downtime(AS_HOST_DOWNTIME_END,time_stamp,temp_subject);
}
}
}
}
/* free memory and close the file */
free(input);
free(input2);
mmap_fclose(thefile);
return;
}
void convert_timeperiod_to_times(int type){
time_t current_time;
struct tm *t;
/* get the current time */
time(¤t_time);
t=localtime(¤t_time);
t->tm_sec=0;
t->tm_min=0;
t->tm_hour=0;
switch(type){
case TIMEPERIOD_LAST24HOURS:
t1=current_time-(60*60*24);
t2=current_time;
break;
case TIMEPERIOD_TODAY:
t1=mktime(t);
t2=current_time;
break;
case TIMEPERIOD_YESTERDAY:
t1=(time_t)(mktime(t)-(60*60*24));
t2=(time_t)mktime(t);
break;
case TIMEPERIOD_THISWEEK:
t1=(time_t)(mktime(t)-(60*60*24*t->tm_wday));
t2=current_time;
break;
case TIMEPERIOD_LASTWEEK:
t1=(time_t)(mktime(t)-(60*60*24*t->tm_wday)-(60*60*24*7));
t2=(time_t)(mktime(t)-(60*60*24*t->tm_wday));
break;
case TIMEPERIOD_THISMONTH:
t->tm_mday=1;
t1=mktime(t);
t2=current_time;
break;
case TIMEPERIOD_LASTMONTH:
t->tm_mday=1;
t2=mktime(t);
if(t->tm_mon==0){
t->tm_mon=11;
t->tm_year--;
}
else
t->tm_mon--;
t1=mktime(t);
break;
case TIMEPERIOD_THISQUARTER:
/* not implemented */
break;
case TIMEPERIOD_LASTQUARTER:
/* not implemented */
break;
case TIMEPERIOD_THISYEAR:
t->tm_mon=0;
t->tm_mday=1;
t1=mktime(t);
t2=current_time;
break;
case TIMEPERIOD_LASTYEAR:
t->tm_mon=0;
t->tm_mday=1;
t2=mktime(t);
t->tm_year--;
t1=mktime(t);
break;
case TIMEPERIOD_LAST7DAYS:
t2=current_time;
t1=current_time-(7*24*60*60);
break;
case TIMEPERIOD_LAST31DAYS:
t2=current_time;
t1=current_time-(31*24*60*60);
break;
default:
break;
}
return;
}
void compute_report_times(void){
time_t current_time;
struct tm *st;
struct tm *et;
/* get the current time */
time(¤t_time);
st=localtime(¤t_time);
st->tm_sec=start_second;
st->tm_min=start_minute;
st->tm_hour=start_hour;
st->tm_mday=start_day;
st->tm_mon=start_month-1;
st->tm_year=start_year-1900;
t1=mktime(st);
et=localtime(¤t_time);
et->tm_sec=end_second;
et->tm_min=end_minute;
et->tm_hour=end_hour;
et->tm_mday=end_day;
et->tm_mon=end_month-1;
et->tm_year=end_year-1900;
t2=mktime(et);
}
/* writes log entries to screen */
void write_log_entries(avail_subject *subject){
archived_state *temp_as;
archived_state *temp_sd;
time_t current_time;
char start_date_time[MAX_DATETIME_LENGTH];
char end_date_time[MAX_DATETIME_LENGTH];
char duration[20];
char *bgclass="";
char *ebgclass="";
char *entry_type="";
char *state_type="";
int days;
int hours;
int minutes;
int seconds;
int odd=0;
if(output_format!=HTML_OUTPUT)
return;
if(show_log_entries==FALSE)
return;
if(subject==NULL)
return;
time(¤t_time);
/* inject all scheduled downtime entries into the main list for display purposes */
for(temp_sd=subject->sd_list;temp_sd!=NULL;temp_sd=temp_sd->next){
switch(temp_sd->entry_type){
case AS_SVC_DOWNTIME_START:
case AS_HOST_DOWNTIME_START:
entry_type="Start of scheduled downtime";
break;
case AS_SVC_DOWNTIME_END:
case AS_HOST_DOWNTIME_END:
entry_type="End of scheduled downtime";
break;
default:
entry_type="?";
break;
}
add_archived_state(temp_sd->entry_type,AS_NO_DATA,temp_sd->time_stamp,entry_type,subject);
}
printf("
\n");
return;
}
/* display hostgroup availability */
void display_hostgroup_availability(void){
hostgroup *temp_hostgroup;
/* display data for a specific hostgroup */
if(show_all_hostgroups==FALSE){
temp_hostgroup=find_hostgroup(hostgroup_name);
display_specific_hostgroup_availability(temp_hostgroup);
}
/* display data for all hostgroups */
else{
for(temp_hostgroup=hostgroup_list;temp_hostgroup!=NULL;temp_hostgroup=temp_hostgroup->next)
display_specific_hostgroup_availability(temp_hostgroup);
}
return;
}
/* display availability for a specific hostgroup */
void display_specific_hostgroup_availability(hostgroup *hg){
unsigned long total_time;
unsigned long time_determinate;
unsigned long time_indeterminate;
avail_subject *temp_subject;
double percent_time_up=0.0;
double percent_time_down=0.0;
double percent_time_unreachable=0.0;
double percent_time_up_known=0.0;
double percent_time_down_known=0.0;
double percent_time_unreachable_known=0.0;
double percent_time_indeterminate=0.0;
double average_percent_time_up=0.0;
double average_percent_time_up_known=0.0;
double average_percent_time_down=0.0;
double average_percent_time_down_known=0.0;
double average_percent_time_unreachable=0.0;
double average_percent_time_unreachable_known=0.0;
double average_percent_time_indeterminate=0.0;
int current_subject=0;
char *bgclass="";
int odd=1;
host *temp_host;
if(hg==NULL)
return;
/* the user isn't authorized to view this hostgroup */
if(is_authorized_for_hostgroup(hg,¤t_authdata)==FALSE)
return;
/* calculate total time during period based on timeperiod used for reporting */
total_time=calculate_total_time(t1,t2);
printf("
\n");
/* write log entries for the host */
temp_subject=find_subject(HOST_SUBJECT,host_name,NULL);
write_log_entries(temp_subject);
}
/* display data for all hosts */
else{
if(output_format==HTML_OUTPUT){
printf("
\n");
}
}
return;
}
void host_report_url(char *hn, char *label){
printf("%s",label);
return;
}
void service_report_url(char *hn, char *sd, char *label){
printf("%s",label);
return;
}
/* calculates running average */
void get_running_average(double *running_average, double new_value, int current_item){
*running_average=(((*running_average*((double)current_item-1.0))+new_value)/(double)current_item);
return;
}
/* used in reports where a timeperiod is selected */
unsigned long calculate_total_time(time_t start_time, time_t end_time){
struct tm *t;
unsigned long midnight_today;
int weekday;
unsigned long total_time;
timerange *temp_timerange;
unsigned long temp_duration;
unsigned long temp_end;
unsigned long temp_start;
unsigned long start;
unsigned long end;
/* attempt to handle the current time_period */
if(current_timeperiod!=NULL){
/* "A day" is 86400 seconds */
t=localtime(&start_time);
/* calculate the start of the day (midnight, 00:00 hours) */
t->tm_sec=0;
t->tm_min=0;
t->tm_hour=0;
midnight_today=(unsigned long)mktime(t);
weekday=t->tm_wday;
total_time=0;
while(midnight_todaymidnight_today)
temp_start=t1-midnight_today;
/* check all time ranges for this day of the week */
for(temp_timerange=current_timeperiod->days[weekday];temp_timerange!=NULL;temp_timerange=temp_timerange->next){
start=max(temp_timerange->range_start,temp_start);
end=min(temp_timerange->range_end,temp_end);
#ifdef DEBUG
printf("