1 /*
2  *  Alarm Pinger (c) 2002 Jacek Konieczny <jajcus@pld.org.pl>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 as published
6  *  by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
16  *  USA
17  *
18  *  $Id: rrd.c,v 1.4 2002/12/20 09:19:08 cvs-jajcus Exp $
19  */
20 
21 #include "config.h"
22 #include "apinger.h"
23 #include "rrd.h"
24 #include "debug.h"
25 
26 #include <stdio.h>
27 #ifdef HAVE_STDLIB_H
28 # include <stdlib.h>
29 #endif
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 # include <string.h>
35 #endif
36 #ifdef HAVE_STDARG_H
37 # include <stdarg.h>
38 #endif
39 
40 #define RRDTOOL_RESTART_TIME (60*5)
41 
42 FILE *rrdtool_pipe=NULL;
43 time_t last_rrdtool_start=0;
44 time_t rrdtool_waiting=0;
45 
rrd_init(void)46 int rrd_init(void){
47 time_t cur_t;
48 
49 	if (rrdtool_pipe)
50 		pclose(rrdtool_pipe);
51 	rrdtool_pipe=NULL;
52 	if (!config->rrd_interval){
53 		return -1;
54 	}
55 	cur_t=time(NULL);
56 	if (cur_t-last_rrdtool_start<RRDTOOL_RESTART_TIME){
57 		if (!rrdtool_waiting)
58 			logit(RRDTOOL " respawning too fast, waiting %is.",RRDTOOL_RESTART_TIME);
59 		rrdtool_waiting=1;
60 		return -1;
61 	}
62 	rrdtool_waiting=0;
63 	last_rrdtool_start=cur_t;
64 	if (foreground && config->debug){
65 		rrdtool_pipe=popen(RRDTOOL " -","w");
66 	}
67 	else{
68 		rrdtool_pipe=popen(RRDTOOL " - >/dev/null 2>&1","w");
69 	}
70 	if (rrdtool_pipe==NULL){
71 		myperror(RRDTOOL);
72 		return -1;
73 	}
74 #if defined(HAVE_SETVBUF) && defined(_IOLBF)
75 	setvbuf(rrdtool_pipe, (char *)NULL, _IOLBF, 0);
76 #endif
77 	return 0;
78 }
79 
rrd_write(const char * format,...)80 int rrd_write(const char *format,...){
81 va_list args;
82 int ret;
83 
84 	va_start(args, format);
85 	if (foreground && config->debug){
86 		vfprintf(stderr, format, args);
87 	}
88 	ret=vfprintf(rrdtool_pipe,format,args);
89 	va_end(args);
90 	return ret;
91 }
92 
rrd_create(void)93 void rrd_create(void){
94 struct target *t;
95 const char *filename;
96 int ret;
97 
98 	for(t=targets;t!=NULL;t=t->next){
99 		if (t->config->rrd_filename==NULL) continue;
100 		filename=subst_macros(t->config->rrd_filename,t,NULL,0);
101 #if defined(HAVE_ACCESS) && defined(F_OK)
102 		if (access(filename,F_OK)==0) continue;
103 #else
104 		{
105 			FILE *f;
106 			f=fopen(filename,"r");
107 			if (f!=NULL){
108 				fclose(f);
109 				continue;
110 			}
111 		}
112 #endif
113 		if (rrdtool_pipe==NULL)
114 			if (rrd_init()) return;
115 		ret=rrd_write("create %s"
116 				" DS:loss:GAUGE:600:0:100"
117 				" DS:delay:GAUGE:600:0:100000"
118 				" RRA:AVERAGE:0.5:1:600"
119 				" RRA:AVERAGE:0.5:6:700"
120 				" RRA:AVERAGE:0.5:24:775"
121 				" RRA:AVERAGE:0.5:288:796\n",filename);
122 		if (ret<0){
123 			myperror("Error while feeding rrdtool");
124 			pclose(rrdtool_pipe);
125 			rrdtool_pipe=NULL;
126 		}
127 	}
128 }
129 
rrd_update(void)130 void rrd_update(void){
131 struct target *t;
132 const char *filename;
133 int ret;
134 
135 	if (sigpipe_received) {
136 		sigpipe_received=0;
137 		if (rrdtool_pipe) pclose(rrdtool_pipe);
138 		rrdtool_pipe=NULL;
139 	}
140 	for(t=targets;t!=NULL;t=t->next){
141 		if (t->config->rrd_filename==NULL) continue;
142 		if (rrdtool_pipe==NULL)
143 			if (rrd_init()) return;
144 		filename=subst_macros(t->config->rrd_filename,t,NULL,0);
145 		ret=rrd_write("update %s -t loss:delay N",filename);
146 		if (ret>0){
147 			if (t->upsent > t->config->avg_loss_delay_samples
148 						+t->config->avg_loss_samples){
149 				ret=rrd_write(":%f",
150 						100*((double)t->recently_lost)/
151 							t->config->avg_loss_samples);
152 			}
153 			else ret=rrd_write(":U");
154 		}
155 		if (ret>0){
156 			if (t->upsent > t->config->avg_delay_samples){
157 				rrd_write(":%f",
158 						(t->delay_sum/t->config->avg_delay_samples)/1000);
159 			}
160 			else ret=rrd_write(":U");
161 		}
162 		if (ret>0)
163 			ret=rrd_write("\n");
164 		if (ret<0){
165 			myperror("Error while feeding rrdtool");
166 			pclose(rrdtool_pipe);
167 			rrdtool_pipe=NULL;
168 		}
169 	}
170 }
171 
rrd_print_cgi(const char * graph_dir,const char * graph_location)172 int rrd_print_cgi(const char *graph_dir,const char *graph_location){
173 struct target_cfg *tc;
174 struct target t;
175 const char *rrd_filename,*p;
176 char *base_filename,*buf,*p1;
177 char *ebuf;
178 int num_esc;
179 
180 	printf("#!" RRDCGI "\n\n");
181 	printf("<HTML>\n<HEAD>\n<TITLE> Alarm Pinger statistics </TITLE>\n</HEAD>\n");
182 	printf("<BODY>\n<H1> Alarm Pinger statistics </H1>\n");
183 	printf("<H2> Daily packet loss and delay summary </H2>\n");
184 	memset(&t,0,sizeof(t));
185 	for(tc=config->targets;tc;tc=tc->next){
186 		if (tc->rrd_filename==NULL) continue;
187 		t.name=tc->name;
188 		t.description=tc->description;
189 		rrd_filename=subst_macros(tc->rrd_filename,&t,NULL,0);
190 		buf=strdup(rrd_filename);
191 		base_filename=strrchr(buf,'/');
192 		if (base_filename!=NULL)
193 			*base_filename++=0;
194 		else
195 			base_filename=buf;
196 		p1=strrchr(base_filename,'.');
197 		if (p1!=NULL) *p1=0;
198 		num_esc=0;
199 		for(p=rrd_filename;*p;p++)
200 			if (*p==':' || *p=='\\') num_esc++;
201 		if (num_esc>0){
202 			ebuf=NEW(char,strlen(rrd_filename)+num_esc+1);
203 			p1=ebuf;
204 			for(p=rrd_filename;*p;p++){
205 				if (*p==':' || *p=='\\') *p1++='\\';
206 				*p1++=*p;
207 			}
208 			*p1++=0;
209 			rrd_filename=ebuf;
210 		}
211 		else ebuf=NULL;
212 		printf("<P><RRD::GRAPH %s/%s-delay.png\n",graph_dir,base_filename);
213 		printf("--imginfo '<IMG SRC=\"%s/%%s\" WIDTH=\"%%lu\" HEIGHT=\"%%lu\">'\n",
214 						graph_location);
215 		printf("-a PNG -h 200 -w 800 --lazy -v 'Packet RTT (s)'\n");
216 		printf("-t 'Packet delay summary for %s (%s)'\n",tc->name,tc->description);
217 		printf("-s -1d -l 0\n");
218 		printf("DEF:delay=%s:delay:AVERAGE\n",rrd_filename);
219 		printf("AREA:delay#00a000:\n");
220 		printf("LINE1:delay#004000:\n");
221 		printf("GPRINT:delay:MIN:\"Minimum\\: %%7.3lf%%ss\"\n");
222 		printf("GPRINT:delay:AVERAGE:\"Average\\: %%7.3lf%%ss\"\n");
223 		printf("GPRINT:delay:MAX:\"Maximum\\: %%7.3lf%%ss\\j\"\n");
224 		printf("></P>");
225 
226 		printf("<P><RRD::GRAPH %s/%s-loss.png\n",graph_dir,base_filename);
227 		printf("--imginfo '<IMG SRC=\"%s/%%s\" WIDTH=\"%%lu\" HEIGHT=\"%%lu\">'\n",
228 						graph_location);
229 		printf("-a PNG -h 200 -w 800 --lazy -v 'Packet loss (%%)'\n");
230 		printf("-t 'Packet loss summary for %s (%s)'\n",tc->name,tc->description);
231 		printf("-s -1d -l 0 -u 100\n");
232 		printf("DEF:loss=%s:loss:AVERAGE\n",rrd_filename);
233 		printf("AREA:loss#f00000:\n");
234 		printf("LINE1:loss#700000:\n");
235 		printf("GPRINT:loss:MIN:\"Minimum\\: %%5.1lf%%%%\"\n");
236 		printf("GPRINT:loss:AVERAGE:\"Average\\: %%5.1lf%%%%\"\n");
237 		printf("GPRINT:loss:MAX:\"Maximum\\: %%5.1lf%%%%\\j\"\n");
238 		printf("></P>\n");
239 		free(buf);
240 		free(ebuf);
241 	}
242 	printf("<P><b>apinger</b> by Jacek Konieczny</P>\n");
243 	printf("</BODY></HTML>\n");
244 	return 0;
245 }
246 
rrd_close(void)247 void rrd_close(void){
248 
249 	if (rrdtool_pipe)
250 		pclose(rrdtool_pipe);
251 }
252