1 /*
2 * File: rrdif.c
3 * Copyright: (c) 2006 by Peter Gritsch
4 * Email: s4nag@no-where.at
5 *
6 * This file is part of SNMP4Nagios.
7 *
8 * SNMP4Nagios is free software; you can redistribute it and/or modify
9 * it under the rets of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * SNMP4Nagios is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with SNMP4Nagios; if not, write to the
20 *
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301, USA
23 */
24
25 #if HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #if(WITH_RRD)
30
31 #include <stdio.h> /* rrd.h needs stdio.h to be included first (type FILE) */
32 #include <rrd.h>
33 #include <dirent.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <syslog.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include "globals.h"
41 #include "nagiosif.h"
42 #include "rrdif.h"
43 #include "syslogif.h"
44 #include "strutils.h"
45
46
TimingGetRange(int aTiming)47 int TimingGetRange ( int aTiming )
48 {
49 int ret = 0;
50
51 switch ( aTiming )
52 {
53 case PLOT_1H_10S: ret = 3600; break;
54 case PLOT_6H_1M: ret = 3600 * 6; break;
55 case PLOT_24H_5M: ret = 3600 * 24; break;
56 case PLOT_7D_15M: ret = 3600 * 24 * 7; break;
57 case PLOT_31D_60M: ret = 3600 * 24 * 31; break;
58 case PLOT_366D_4H: ret = 3600 * 24 * 366; break;
59 default: Error ( LOG_ERR, "Invalid timing" ); break;
60 }
61 return ret;
62 }
63
TimingGetInterval(int aTiming)64 int TimingGetInterval ( int aTiming )
65 {
66 int ret = 0;
67
68 switch ( aTiming )
69 {
70 case PLOT_1H_10S: ret = 10; break;
71 case PLOT_6H_1M: ret = 60; break;
72 case PLOT_24H_5M: ret = 60 * 5; break;
73 case PLOT_7D_15M: ret = 60 * 15; break;
74 case PLOT_31D_60M: ret = 60 * 60; break;
75 case PLOT_366D_4H: ret = 60 * 40 * 4; break;
76 default: Error ( LOG_ERR, "Invalid timing" ); break;
77 }
78 return ret;
79 }
80
TimingGetXScale(int aTiming)81 float TimingGetXScale ( int aTiming )
82 {
83 float ret = 1.00;
84
85 switch ( aTiming )
86 {
87 case PLOT_1H_10S: ret = 1.00; break;
88 case PLOT_6H_1M: ret = 1.00; break;
89 case PLOT_24H_5M: ret = 2.00; break;
90 case PLOT_7D_15M: ret = 1.00; break;
91 case PLOT_31D_60M: ret = 1.00; break;
92 case PLOT_366D_4H: ret = 0.25; break;
93 default: Error ( LOG_ERR, "Invalid timing" ); break;
94 }
95 return ret;
96 }
97
TimingGetDescr(int aTiming)98 char* TimingGetDescr ( int aTiming )
99 {
100 char* ret = NULL;
101
102 switch ( aTiming )
103 {
104 case PLOT_1H_10S: ret = StrDup ( "1h_10s" ); break;
105 case PLOT_6H_1M: ret = StrDup ( "6h_1m" ); break;
106 case PLOT_24H_5M: ret = StrDup ( "24h_5m" ); break;
107 case PLOT_7D_15M: ret = StrDup ( "7d_15m" ); break;
108 case PLOT_31D_60M: ret = StrDup ( "31d_1h" ); break;
109 case PLOT_366D_4H: ret = StrDup ( "366d_4h" ); break;
110 default: Error ( LOG_ERR, "Invalid timing" ); break;
111 }
112 return ret;
113 }
114
CheckDir(const char * aDir)115 void CheckDir ( const char* aDir )
116 {
117 DIR* dir = opendir ( aDir );
118
119 if ( dir )
120 {
121 closedir ( dir );
122 } else
123 {
124 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
125 /* mkdir returns 0(!) on success, -1 on failure */
126 if ( mkdir ( aDir, mode ) )
127 {
128 char msg[1024];
129 snprintf ( msg, 1024,
130 "Could not make directory %s.\n",
131 aDir );
132 Error ( LOG_ERR, msg );
133 }
134 }
135 }
136
BuildRRDFilePath(const char * aRRDHostDirPath)137 char* BuildRRDFilePath ( const char* aRRDHostDirPath )
138 {
139 char* ret;
140 char* part;
141
142 if ( hasAddInfParam ) part = StrConcat ( 4, srvName, "_", addInf, ".rrd" );
143 else part = StrConcat ( 2, srvName, ".rrd" );
144 ret = StrConcat ( 3, aRRDHostDirPath, "/", part );
145 free ( part );
146 return ret;
147 }
148
149
CheckRRDDataFile(const char * dataFile)150 void CheckRRDDataFile ( const char* dataFile )
151 {
152 FILE* file = fopen ( dataFile, "r+" );
153
154 if ( file ) fclose ( file );
155 else CreateDataFile ( dataFile );
156 }
157
CreateDSStr(const char * aName,int aType,int aHBeat,char * aMin,char * aMax)158 char* CreateDSStr ( const char* aName, int aType, int aHBeat, char* aMin,
159 char* aMax )
160 {
161 char* ret;
162 char* type = NULL;
163 char* hBeat = IntToStr ( aHBeat );
164
165 switch ( aType )
166 {
167 case GAUGE: type = "GAUGE"; break;
168 case COUNTER: type = "COUNTER"; break;
169 case DERIVE: type = "DERIVE"; break;
170 case ABSOLUTE: type = "ABSOLUTE"; break;
171 default:
172 {
173 char msg[1024];
174
175 snprintf ( msg, 1024,
176 "Invalid type of DS: %i.\n", aType );
177 Error ( LOG_ERR, msg );
178 }
179 break;
180 }
181 ret = StrConcat ( 10, "DS:", aName, ":", type, ":", hBeat, ":",
182 aMin, ":", aMax );
183 return ( ret );
184 }
185
CreateRRAStr(int aCF,int aRangeHours,int aCDPIntMinutes)186 char* CreateRRAStr ( int aCF, int aRangeHours, int aCDPIntMinutes )
187 {
188 char* ret;
189 char* cf = NULL;
190 int secondsPerCDP = 60 * aCDPIntMinutes;
191 int secondsRange = 60 * 60 * aRangeHours;
192 char* cdpPerPDP = IntToStr ( secondsPerCDP / rrdStep );
193 char* rows = IntToStr ( secondsRange / secondsPerCDP );
194
195 switch ( aCF )
196 {
197 case MIN: cf = "MIN"; break;
198 case MAX: cf = "MAX"; break;
199 case AVG: cf = "AVERAGE"; break;
200 case LST: cf = "LAST"; break;
201 default:
202 {
203 char msg[1024];
204
205 snprintf ( msg, 1024,
206 "Invalid consolidating function for RRA: %i.\n", aCF );
207 Error ( LOG_ERR, msg );
208 }
209 break;
210 }
211 ret = StrConcat ( 6, "RRA:", cf, ":0.5:", cdpPerPDP, ":", rows );
212 free ( rows );
213 free ( cdpPerPDP );
214 return ret;
215 }
216
RRDCreate(int aParamCnt,char ** aParams,const char * aRRDFilePath)217 void RRDCreate ( int aParamCnt, char** aParams, const char* aRRDFilePath )
218 {
219 int chk;
220
221 LogParams ( aParamCnt, aParams );
222 optind = 1; /* rrd_*'s weired interface */
223 rrd_clear_error ();
224 /* rrd_* functions return 0 on success. */
225 chk = rrd_create ( aParamCnt, aParams );
226 CheckRRDError ( chk, "create", aRRDFilePath );
227 }
228
RRDUpdate(int aParamCnt,char ** aParams,const char * aRRDFilePath)229 void RRDUpdate ( int aParamCnt, char** aParams, const char* aRRDFilePath )
230 {
231 int chk;
232
233 LogParams ( aParamCnt, aParams );
234 optind = 1; /* rrd_*'s weired interface */
235 rrd_clear_error ();
236 /* rrd_* functions return 0 on success. */
237 chk = rrd_update ( aParamCnt, aParams );
238 CheckRRDError ( chk, "update", aRRDFilePath );
239 }
240
BuildPNGFileName(const char * aPltId,int aTiming)241 char* BuildPNGFileName ( const char* aPltId, int aTiming )
242 {
243 char* ret;
244 char* ai;
245 char* pi;
246 char* ti;
247
248 if ( hasAddInfParam ) ai = StrConcat ( 2, "_", addInf );
249 else ai = StrDup ( "" );
250 if ( NULL != aPltId ) pi = StrConcat ( 2, "_", aPltId );
251 else pi = StrDup ( "" );
252 ti = TimingGetDescr ( aTiming );
253 ret = StrConcat ( 6, srvName, ai, pi, "_", ti, ".png" );
254 /* ti is not a malloced string */
255 free ( ai );
256 free ( pi );
257 return ret;
258 }
259
BuildPNGFilePath(const char * aPNGHostDir,const char * aPNGFileName)260 char* BuildPNGFilePath ( const char* aPNGHostDir, const char* aPNGFileName )
261 {
262 char* ret;
263
264 ret = StrConcat ( 3, aPNGHostDir, "/", aPNGFileName );
265 return ret;
266 }
267
BuildTmpPNGFilePath(const char * aPNGFilePath)268 char* BuildTmpPNGFilePath ( const char* aPNGFilePath )
269 {
270 char* ret;
271 char* pid;
272
273 pid = IntToStr ( getpid() );
274 ret = StrConcat ( 3, aPNGFilePath, ".", pid );
275 free ( pid );
276 return ret;
277 }
278
FNInit()279 tFN* FNInit ()
280 {
281 tFN* fn;
282
283 fn = malloc ( sizeof ( tFN ) );
284 if ( fn == NULL ) ErrorMalloc ();
285 fn->rrdHostDirPath = GetRRDHostDirPath ();
286 fn->rrdFilePath = BuildRRDFilePath ( fn->rrdHostDirPath );
287 fn->pngHostDirName = GetPNGHostDirName ();
288 fn->pngFileName = NULL;
289 fn->pngFilePath = NULL;
290 fn->tmpPNGFilePath = NULL;
291 CheckDir ( fn->pngHostDirName );
292 return fn;
293 }
294
FNDone(tFN * aFN)295 void FNDone ( tFN* aFN )
296 {
297 FNUnsetPNGData ( aFN );
298 free ( aFN->pngHostDirName );
299 free ( aFN->rrdFilePath );
300 free ( aFN->rrdHostDirPath );
301 free ( aFN );
302 }
303
FNSetPNGData(tFN * aFN,const char * aPlotId,int aTiming)304 void FNSetPNGData ( tFN* aFN, const char* aPlotId, int aTiming )
305 {
306 FNUnsetPNGData ( aFN );
307 aFN->pngFileName = BuildPNGFileName ( aPlotId, aTiming );
308 aFN->pngFilePath = BuildPNGFilePath ( aFN->pngHostDirName,
309 aFN->pngFileName );
310 aFN->tmpPNGFilePath = BuildTmpPNGFilePath ( aFN->pngFilePath );
311 }
312
FNUnsetPNGData(tFN * aFN)313 void FNUnsetPNGData ( tFN* aFN )
314 {
315 if ( aFN->tmpPNGFilePath != NULL ) free ( aFN->tmpPNGFilePath );
316 if ( aFN->pngFilePath != NULL ) free ( aFN->pngFilePath );
317 if ( aFN->pngFileName != NULL ) free ( aFN->pngFileName );
318 aFN->tmpPNGFilePath = NULL;
319 aFN->pngFilePath = NULL;
320 aFN->pngFileName = NULL;
321 }
322
PPInit()323 tPP* PPInit ()
324 {
325 tPP* pp;
326 pp = malloc ( sizeof ( tPP ) );
327 if ( pp == NULL ) ErrorMalloc ();
328 pp->dim = NULL;
329 pp->unit = NULL;
330 pp->stack = NULL;
331 pp->count = 0;
332 pp->dimLen = 0;
333 pp->unitLen = 0;
334 return pp;
335 }
336
PPAddPlot(tPP * aPP,const char * aDim,const char * aUnit,int aStack)337 void PPAddPlot ( tPP* aPP, const char* aDim, const char* aUnit, int aStack )
338 {
339 int index = aPP->count;
340 int dimLen = strlen ( aDim );
341 int unitLen = strlen ( aUnit );
342
343 aPP->count++;
344 if ( aPP->count == 1 )
345 {
346 aPP->dim = malloc ( sizeof ( char* ) );
347 aPP->unit = malloc ( sizeof ( char* ) );
348 aPP->stack = malloc ( sizeof ( int ) );
349 } else
350 {
351 aPP->dim = realloc ( aPP->dim, sizeof ( char* ) * aPP->count );
352 aPP->unit = realloc ( aPP->unit, sizeof ( char* ) * aPP->count );
353 aPP->stack = realloc ( aPP->stack, sizeof ( int ) * aPP->count );
354 }
355 if ( aPP->dim == NULL ) ErrorMalloc ();
356 if ( aPP->unit == NULL ) ErrorMalloc ();
357 if ( aPP->stack == NULL ) ErrorMalloc ();
358 aPP->dim[index] = StrDup ( aDim );
359 aPP->unit[index] = StrDup ( aUnit );
360 aPP->stack[index] = aStack;
361 if ( aStack ) dimLen += strlen ( "[+] " );
362 if ( dimLen > aPP->dimLen ) aPP->dimLen = dimLen;
363 if ( unitLen > aPP->unitLen ) aPP->unitLen = unitLen;
364 }
365
PPDone(tPP * aPP)366 void PPDone ( tPP* aPP )
367 {
368 while ( aPP->count > 0 )
369 {
370 aPP->count--;
371 free ( aPP->unit[aPP->count] );
372 free ( aPP->dim[aPP->count] );
373 }
374 free ( aPP->stack );
375 free ( aPP->unit );
376 free ( aPP->dim );
377 free ( aPP );
378 }
379
PlotStdParams(char ** aParams,tFN * aFN,const char * aTitle,const char * aVLabel,int aTiming,int aEnd,int aSIBase,int aSIExp,int aLower,int aUpper,int aUsingBidir)380 int PlotStdParams ( char** aParams, tFN* aFN, const char* aTitle,
381 const char* aVLabel, int aTiming, int aEnd, int aSIBase, int aSIExp,
382 int aLower, int aUpper, int aUsingBidir )
383 {
384 int range = TimingGetRange ( aTiming );
385 int interval = TimingGetInterval ( aTiming );
386 float xScale = TimingGetXScale ( aTiming );
387 int start = aEnd - range;
388 int w1 = (int) ( ( (float) ( range / interval ) ) * xScale );
389 int h1 = ( aUsingBidir ) ? PLOT_H_BIDIR : PLOT_H_UNIDIR;
390 int i = 0;
391 int usingExp = TRUE;
392 int exp = 0;
393
394 printf ( "TITLE %s\n", aTitle );
395 printf ( "START %i\n", start );
396 printf ( "END %i\n", aEnd );
397 switch ( aSIExp )
398 {
399 case PLOT_SI_AUTO: usingExp = FALSE; break;
400 case PLOT_SI_FEMTO: exp = -15; break;
401 case PLOT_SI_PICO: exp = -12; break;
402 case PLOT_SI_NANO: exp = -9; break;
403 case PLOT_SI_MICRO: exp = -6; break;
404 case PLOT_SI_MILLI: exp = -3; break;
405 case PLOT_SI_NONE: exp = 0; break;
406 case PLOT_SI_KILO: exp = 3; break;
407 case PLOT_SI_MEGA: exp = 6; break;
408 case PLOT_SI_GIGA: exp = 9; break;
409 case PLOT_SI_TERA: exp = 12; break;
410 case PLOT_SI_PETA: exp = 15; break;
411 default: Error ( LOG_ERR, "Invalid SI Exponent Name given" );
412 }
413 aParams [i++] = StrDup ( "JUNK" );
414 aParams [i++] = StrDup ( aFN->tmpPNGFilePath );
415 aParams [i++] = StrDup ( "-t" );
416 aParams [i++] = StrDup ( aTitle );
417 aParams [i++] = StrDup ( "-v" );
418 aParams [i++] = StrDup ( aVLabel );
419 aParams [i++] = StrDup ( "-b" );
420 aParams [i++] = IntToStr ( aSIBase );
421 if ( usingExp )
422 {
423 aParams [i++] = StrDup ( "-X" );
424 aParams [i++] = IntToStr ( exp );
425 }
426 if ( aLower < aUpper )
427 {
428 aParams [i++] = StrDup ( "-l" );
429 aParams [i++] = IntToStr ( aLower );
430 aParams [i++] = StrDup ( "-u" );
431 aParams [i++] = IntToStr ( aUpper );
432 }
433 aParams [i++] = StrDup ( "-s" );
434 aParams [i++] = IntToStr ( start );
435 aParams [i++] = StrDup ( "-e" );
436 aParams [i++] = IntToStr ( aEnd );
437 aParams [i++] = StrDup ( "-w" );
438 aParams [i++] = IntToStr ( w1 );
439 aParams [i++] = StrDup ( "-h" );
440 aParams [i++] = IntToStr ( h1 );
441 aParams [i++] = StrDup ( "-a" );
442 aParams [i++] = StrDup ( "PNG" );
443 return i;
444 }
445
CreateDEF(const char * aVName,tFN * aFN,const char * aDS,int aCF)446 char* CreateDEF ( const char* aVName, tFN* aFN, const char* aDS,
447 int aCF )
448 {
449 char* ret;
450 char* cf = NULL;
451
452 switch ( aCF )
453 {
454 case MIN: cf = "MIN"; break;
455 case MAX: cf = "MAX"; break;
456 case AVG: cf = "AVERAGE"; break;
457 case LST: cf = "LAST"; break;
458 default:
459 Error ( LOG_CRIT, "Invalid aCF passed to CreateDEF()." );
460 break;
461 }
462 ret = StrConcat ( 8, "DEF:", aVName, "=", aFN->rrdFilePath, ":", aDS,
463 ":", cf );
464 return ret;
465 }
466
CreatePlot(int aType,const char * aVName,const char * aColor,tPP * aPP,int aPPI,int aCF,int aNL)467 char* CreatePlot ( int aType, const char* aVName, const char* aColor,
468 tPP* aPP, int aPPI, int aCF, int aNL )
469 {
470 char* ret;
471 char* type = NULL;
472 char* cf = NULL;
473 char* stack = aPP->stack[aPPI] ? "[+] " : "";
474
475 switch ( aType )
476 {
477 case PLOT_AREA: type = "AREA"; break;
478 case PLOT_LINE1: type = "LINE1"; break;
479 case PLOT_LINE2: type = "LINE2"; break;
480 case PLOT_LINE3: type = "LINE3"; break;
481 case PLOT_STACK: type = "STACK"; break;
482 default:
483 Error ( LOG_CRIT, "Invalid aType passed to CreatePlot()." );
484 break;
485 }
486 switch ( aCF )
487 {
488 case MIN: cf = "min"; break;
489 case MAX: cf = "max"; break;
490 case AVG: cf = "avg"; break;
491 case LST: cf = "lst"; break;
492 default:
493 Error ( LOG_CRIT, "Invalid aCF passed to CreatePlot()." );
494 break;
495 }
496 if ( aNL )
497 {
498 ret = StrConcat ( 10, type, ":", aVName, aColor, ":", stack,
499 aPP->dim[aPPI], ", ", cf, "\\n" );
500 } else
501 {
502 char* padStr;
503 int i;
504 /* Start with the length of the longest dimension string */
505 int padLen = aPP->dimLen;
506
507 /* add two blanks (inter-column space) */
508 padLen += 2;
509 /* add the length of the cf string TODO: Why? */
510 /* TODO padLen += 3; */
511 /* subtract the length of this dimension string */
512 padLen -= strlen ( aPP->dim[aPPI] );
513 /* subtract the length of the stack string (may be 0) */
514 padLen -= strlen ( stack );
515 /* create the padding string */
516 padStr = malloc ( padLen + 1 );
517 for ( i = 0; i < padLen; i++ ) padStr [i] = ' ';
518 padStr [padLen] = '\000';
519 ret = StrConcat ( 10 , type, ":", aVName, aColor, ":", stack,
520 aPP->dim[aPPI], ", ", cf, padStr );
521 free ( padStr );
522 }
523 return ret;
524 }
525
PlotPrintParams(int aI,char ** aParams,tPP * aPP,int aPPI,const char * aVNAvg,const char * aVNMin,const char * aVNMax,const char * aVNLst,const char * aFormat)526 int PlotPrintParams (int aI, char** aParams, tPP* aPP, int aPPI,
527 const char* aVNAvg, const char* aVNMin, const char* aVNMax,
528 const char* aVNLst, const char* aFormat )
529 {
530 int i = aI;
531
532 aParams [i++] = StrConcat ( 4, "PRINT:", aVNAvg, ":AVERAGE:AVG ", aFormat );
533 aParams [i++] = StrConcat ( 4, "PRINT:", aVNMin, ":MIN:MIN ", aFormat );
534 aParams [i++] = StrConcat ( 4, "PRINT:", aVNMax, ":MAX:MAX ", aFormat );
535 aParams [i++] = StrConcat ( 4, "PRINT:", aVNLst, ":LAST:LST ", aFormat );
536 return i;
537 }
538
RRDGraph(int aParamCnt,char ** aParams,tFN * aFN,tPP * aPP)539 void RRDGraph ( int aParamCnt, char** aParams, tFN* aFN, tPP* aPP )
540 {
541 int chk = -1;
542 int w;
543 int h;
544 char** results;
545 int j = 0;
546 #if(NEW_RRD_GRAPH)
547 double j1;
548 double j2;
549 #endif
550
551 LogParams ( aParamCnt, aParams );
552 optind = 1; /* rrd_*'s weired interface */
553 rrd_clear_error ();
554 /* rrd_* functions return 0 on success. */
555 chk = rrd_graph ( aParamCnt, aParams, &results, &w, &h
556 #if(NEW_RRD_GRAPH)
557 , NULL, &j1, &j2
558 #endif
559 );
560 CheckRRDError ( chk, "graph", aFN->rrdFilePath );
561 if ( rename ( aFN->tmpPNGFilePath, aFN->pngFilePath ) == -1 )
562 Error ( LOG_ERR, "Could not rename file" );
563 printf ( "IMAGE %s\n", aFN->pngFileName );
564 printf ( "WIDTH %i\n", w );
565 printf ( "HEIGHT %i\n", h );
566 while ( results [j] )
567 {
568 if ( ( j % 4 ) == 0 )
569 {
570 int i = j / 4;
571
572 if ( i < aPP->count )
573 {
574 printf ( "DIMENSION %s\n", aPP->dim[i] );
575 printf ( "UNIT %s\n", aPP->unit[i] );
576 }
577 }
578 printf ( "%s\n", results [j++] );
579 }
580 printf ( "END\n" );
581 while ( j > 0 ) free ( results [--j] );
582 free ( results );
583 }
584
LogPerfData()585 void LogPerfData ()
586 {
587 char* hostDirPath = GetRRDHostDirPath ();
588 char* rrdFilePath = BuildRRDFilePath ( hostDirPath );
589
590 CheckDir ( hostDirPath );
591 CheckRRDDataFile ( rrdFilePath );
592 if ( !checkData )
593 {
594 char* data = GetData ();
595 ParseData ( data );
596 free ( data );
597 } /* else the global variable v should already contain the parsed data. */
598 WriteData ( rrdFilePath );
599 free ( rrdFilePath );
600 free ( hostDirPath );
601 }
602
603 #endif /* WITH_RRD */
604