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