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