/**************************************************************************
*
* AVAIL.C - NetSaint Availability CGI
*
* Copyright (c) 2000-2001 Ethan Galstad (netsaint@netsaint.org)
* Last Modified: 12-21-2001
*
* License:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*************************************************************************/
#include "../common/config.h"
#include "../common/locations.h"
#include "../common/common.h"
#include "../common/objects.h"
#include "../common/comments.h"
#include "../common/statusdata.h"
#include "cgiutils.h"
#include "getcgi.h"
#include "auth.h"
#include "edata.h"
/*#define DEBUG*/
/* output types */
#define HTML_OUTPUT 0
#define CSV_OUTPUT 1
/* archived state types */
#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
/* display types */
#define DISPLAY_NO_AVAIL 0
#define DISPLAY_HOSTGROUP_AVAIL 1
#define DISPLAY_HOST_AVAIL 2
#define DISPLAY_SERVICE_AVAIL 3
/* 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 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;
char *state_info;
struct archived_state_struct *next;
}archived_state;
typedef struct avail_subject_struct{
int type;
char *host_name;
char *service_description;
archived_state *as_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;
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 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_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_services=FALSE;
int assume_initial_states=TRUE;
int assume_state_retention=TRUE;
int assume_initial_state_ok=TRUE;
char *hostgroup_name="";
char *host_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 *);
void display_hostgroup_availability(void);
void display_specific_hostgroup_availability(hostgroup *);
void display_host_availability(void);
void display_service_availability(void);
void write_log_entries(avail_subject *);
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,time_t,char *);
void add_archived_state(int,time_t,char *,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);
void document_header(int);
void document_footer(void);
int process_cgivars(void);
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 hostgroup *hostgroup_list;
extern host *host_list;
extern service *service_list;
extern int log_rotation_method;
extern time_t last_scheduled_log_rotation;
int backtrack_archives=2;
int earliest_archive=0;
int embedded=FALSE;
int display_header=TRUE;
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;
time_t t3;
time_t current_time;
struct tm *t;
/* initialize time period to last 24 hours */
time(&t2);
t1=(time_t)(t2-(60*60*24));
/* get the arguments passed in the URL */
process_cgivars();
/* reset internal CGI variables */
reset_cgi_vars();
/* read the CGI configuration file */
result=read_cgi_config_file(DEFAULT_CGI_CONFIG_FILE);
if(result==ERROR){
document_header(FALSE);
printf("
Error: Could not open CGI configuration file '%s' for reading!
\n",DEFAULT_CGI_CONFIG_FILE);
document_footer();
return ERROR;
}
document_header(TRUE);
/* read the main configuration file */
result=read_main_config_file(main_config_file);
if(result==ERROR){
printf("
Error: Could not open main configuration file '%s' for reading!
\n",main_config_file);
document_footer();
return ERROR;
}
/* read all object configuration data */
result=read_all_object_configuration_data(main_config_file,READ_HOSTGROUPS|READ_CONTACTGROUPS|READ_CONTACTS|READ_HOSTS|READ_SERVICES);
if(result==ERROR){
printf("
Error: Could not read some or all object configuration data!
\n");
document_footer();
return ERROR;
}
/* read all status data */
result=read_all_status_data(DEFAULT_CGI_CONFIG_FILE,READ_PROGRAM_STATUS|READ_HOST_STATUS|READ_SERVICE_STATUS);
if(result==ERROR){
printf("
Error: Could not read host and service status information!
\n");
document_footer();
return ERROR;
}
/* 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(t2\n");
printf("
\n");
if(display_type==DISPLAY_HOST_AVAIL && show_all_hosts==FALSE){
host_report_url("all","View Availability Report For All Hosts");
printf(" \n");
printf("View Trends For This Host \n",TRENDS_CGI,url_encode(host_name),t1,t2,(assume_state_retention==TRUE)?"on":"off",(assume_initial_states==TRUE)?"on":"off",backtrack_archives);
printf("View Status Detail For This Host \n",STATUS_CGI,url_encode(host_name));
printf("View 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");
printf("View Trends For This Service \n",url_encode(svc_description),t1,t2,(assume_state_retention==TRUE)?"on":"off",(assume_initial_states==TRUE)?"on":"off",backtrack_archives);
printf("View History This Service \n",url_encode(svc_description));
printf("View Notifications This Service \n",url_encode(svc_description));
}
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 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,NULL),¤t_authdata);
else
is_authorized=is_authorized_for_service(find_service(host_name,svc_description,NULL),¤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
display_hostgroup_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 Type Of Availability Report
\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\n");
printf("Pragma: no-cache\n");
time(¤t_time);
get_time_string(¤t_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
printf("Last-Modified: %s\n",date_time);
expire_time=(time_t)0;
get_time_string(&expire_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
printf("Expires: %s\n",date_time);
if(output_format==HTML_OUTPUT)
printf("Content-type: text/html\n\n");
else{
printf("Content-type: text/plain\n\n");
return;
}
if(embedded==TRUE)
return;
printf("\n");
printf("\n");
printf("\n");
printf("NetSaint Availability\n");
printf("\n");
if(use_stylesheet==TRUE)
printf("\n",url_stylesheets_path,AVAIL_CSS);
printf("\n");
printf("\n");
return;
}
void document_footer(void){
if(output_format!=HTML_OUTPUT)
return;
if(embedded==TRUE)
return;
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]);
display_type=DISPLAY_HOSTGROUP_AVAIL;
show_all_hostgroups=(strcmp(hostgroup_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]);
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]);
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],"on"))
assume_initial_states=TRUE;
else
assume_initial_states=FALSE;
}
/* we found the assume initial state ok option */
else if(!strcmp(variables[x],"assumeinitialstateok")){
x++;
if(variables[x]==NULL){
error=TRUE;
break;
}
if(!strcmp(variables[x],"on"))
assume_initial_state_ok=TRUE;
else
assume_initial_state_ok=FALSE;
}
/* 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],"on"))
assume_state_retention=TRUE;
else
assume_state_retention=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],"custom"))
timeperiod_type=TIMEPERIOD_CUSTOM;
else
return error;
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],"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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
end_hour=atoi(variables[x]);
timeperiod_type=TIMEPERIOD_CUSTOM;
compute_time_from_parts=TRUE;
}
}
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);
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 graph_end_data=TRUE;
int have_some_real_data=FALSE;
hoststatus *hststatus=NULL;
servicestatus *svcstatus=NULL;
int first_real_state=AS_NO_DATA;
int initial_assumed_state=AS_NO_DATA;
time_t initial_assumed_time;
int wobble=300;
/* if left hand of graph is after current time, we can't do anything at all.... */
if(t1>current_time)
return;
/* check to see if we have any real data whatsoever... */
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;
first_real_state=temp_as->entry_type;
break;
}
}
/* if we don't have any data, assume current state (if possible) */
if(have_some_real_data==FALSE){
/* current time DOES NOT fall within graph bounds, so we can't do anything */
/* the "wobble" value is necessary because when the CGI is called to do the PNG generation, t2 will actually be less that current_time by a bit */
if(current_time(t2+wobble))
return;
if(subject->type==HOST_SUBJECT)
subject->last_known_state=AS_HOST_UP;
else
subject->last_known_state=AS_SVC_OK;
/* 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){
hststatus=find_hoststatus(host_name);
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
subject->last_known_state=AS_HOST_UP;
}
/* add a dummy archived state item, so something can get graphed */
add_archived_state(subject->last_known_state,t1,"Current Host State (Assumed)",subject);
}
else{
svcstatus=find_servicestatus(host_name,svc_description);
if(svcstatus!=NULL){
if(svcstatus->status==SERVICE_OK || svcstatus->status==SERVICE_RECOVERY)
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 || svcstatus->status==SERVICE_HOST_DOWN || svcstatus->status==SERVICE_UNREACHABLE)
subject->last_known_state=AS_SVC_CRITICAL;
else if(svcstatus->status==SERVICE_UNKNOWN)
subject->last_known_state=AS_SVC_UNKNOWN;
}
/* add a dummy archived state item, so something can get graphed */
add_archived_state(subject->last_known_state,t1,"Current Service State (Assumed)",subject);
}
}
/* we do have some real data, so insert initial (assumed) state if we can */
else if(assume_initial_states==TRUE){
/* we're assuming initial states of either OK or UP (for service or host) */
if(assume_initial_state_ok==TRUE){
if(subject->type==HOST_SUBJECT)
initial_assumed_state=AS_HOST_UP;
else
initial_assumed_state=AS_SVC_OK;
}
/* else assume initial state is the same as the first 'real' state we encountered */
else
initial_assumed_state=first_real_state;
/* add this assumed state entry before any entries in the list and <= t1 */
if(subject->as_list->time_stamp>t1)
initial_assumed_time=t1;
else
initial_assumed_time=subject->as_list->time_stamp-1;
/* add initial state as first entry */
if(subject->type==HOST_SUBJECT)
add_archived_state(initial_assumed_state,initial_assumed_time,"Assumed Initial Host State (Faked Log Entry)",subject);
else
add_archived_state(initial_assumed_state,initial_assumed_time,"Assumed Initial Service State (Faked Log Entry)",subject);
}
last_as=NULL;
subject->earliest_time=t2;
subject->latest_time=t1;
/**********************************/
/* BEGINNING/MIDDLE SECTION */
/**********************************/
for(temp_as=subject->as_list;temp_as!=NULL;temp_as=temp_as->next){
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 preceeds 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);
/* return if we've reached the end of the graph limits */
if(b>=t2)
break;
}
/* else we're still before the first time on the graph, but keep this as the last know state (if possible) */
else if(b<=t1){
if(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;
}
}
last_as=temp_as;
/* special case for first entry in list */
if(temp_as==subject->as_list){
if(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;
}
}
/**********************************/
/* END SECTION */
/**********************************/
if(subject->as_list!=NULL){
time(¤t_time);
b=current_time;
if(b>t2)
b=t2;
/* fake the current state (it doesn't really matter for graphing) */
if(subject->type==HOST_SUBJECT)
current_state=AS_HOST_UP;
else
current_state=AS_SVC_OK;
/***** SPECIAL CASE - THERE WAS ONLY ONE ENTRY IN THE LIST *****/
if(subject->latest_time<=t1){
compute_subject_availability_times(subject->as_list->entry_type,current_state,subject->as_list->time_stamp,subject->as_list->time_stamp,b,subject);
}
/***** NORMAL CASE - THERE WERE TWO OR MORE ENTRIES IN THE LIST *****/
else{
/* the timestamp on the last data point has to be within the graph bounds */
if(subject->latest_time < b){
compute_subject_availability_times(last_as->entry_type,current_state,subject->latest_time,subject->latest_time,b,subject);
}
}
}
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){
int start_state;
int end_state;
/* can't graph if we don't have data... */
if(first_state==AS_NO_DATA || last_state==AS_NO_DATA)
return;
if(first_state==AS_PROGRAM_START && (last_state==AS_PROGRAM_END || last_state==AS_PROGRAM_START)){
if(assume_initial_states==FALSE)
return;
}
if(first_state==AS_PROGRAM_END)
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;
/* clip times if necessary */
if(start_timet2)
end_time=t2;
/* make sure this is a valid time */
if(start_time>t2)
return;
if(end_timetime_up+=(unsigned long)(end_time-start_time);
break;
case AS_HOST_DOWN:
subject->time_down+=(unsigned long)(end_time-start_time);
break;
case AS_HOST_UNREACHABLE:
subject->time_unreachable+=(unsigned long)(end_time-start_time);
break;
case AS_SVC_OK:
subject->time_ok+=(unsigned long)(end_time-start_time);
break;
case AS_SVC_WARNING:
subject->time_warning+=(unsigned long)(end_time-start_time);
break;
case AS_SVC_UNKNOWN:
subject->time_unknown+=(unsigned long)(end_time-start_time);
break;
case AS_SVC_CRITICAL:
subject->time_critical+=(unsigned long)(end_time-start_time);
break;
default:
break;
}
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;
host *temp_host;
service *temp_service;
/* 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, so use all hosts */
if(show_all_hostgroups==TRUE){
for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next)
add_subject(HOST_SUBJECT,temp_host->name,NULL);
}
/* we're only displaying a specific hostgroup */
else{
temp_hostgroup=find_hostgroup(hostgroup_name,NULL);
if(temp_hostgroup!=NULL){
for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
if(is_host_member_of_hostgroup(temp_hostgroup,temp_host)==TRUE)
add_subject(HOST_SUBJECT,temp_host->name,NULL);
}
}
}
}
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;
/* 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,NULL),¤t_authdata);
else
is_authorized=is_authorized_for_service(find_service(hn,sd,NULL),¤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 fo 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 fo 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->as_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 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(state_type,time_stamp,state_info,temp_subject);
return;
}
/* adds an archived state entry to a specific subject */
void add_archived_state(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 fo 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;
new_as->entry_type=state_type;
new_as->time_stamp=time_stamp;
/* add the new entry to the list in memory, sorted by time */
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;
}
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(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_archivetm_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;
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;
char start_date_time[MAX_DATETIME_LENGTH];
char end_date_time[MAX_DATETIME_LENGTH];
char duration[17];
char *bgclass="";
char *ebgclass="";
char *entry_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;
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("