1 /*
2  * File:      check_ucd_mem.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 terms 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 #include <errno.h>
30 #include "globals.h"
31 #include "nagiosif.h"
32 #if(WITH_RRD)
33 #include "rrdif.h"
34 #endif /* WITH_RRD */
35 #include "snmpif.h"
36 #include "syslogif.h"
37 #include "strutils.h"
38 #include "utilities.h"
39 
40 
41 /* data type for storing scan results */
42 /* Note: VMware ESX reports negative values for this. I've got to catch it. */
43 typedef struct
44 {
45     int v3;      /* found memTotalSwap and is OK */
46     int v4;      /* found memAvailSwap and is OK */
47     int v5;      /* found memTotalReal and is OK */
48     int v6;      /* found memAvailReal and is OK */
49     int v11;     /* found memTotalFree and is OK */
50     int v13;     /* found memShared and is OK */
51     int v14;     /* found memBuffer and is OK */
52     int v15;     /* found memCached and is OK */
53 } tScanRes;
54 
55 /* data type for storing data */
56 typedef struct
57 {
58     int    sTotal; /* total swap space */
59     int    sAvail; /* available swap space */
60     int    rTotal; /* total real/physical memory */
61     int    rAvail; /* available real/physical memory */
62     int    tAvail; /* total available (free) memory */
63     int    shared; /* shared memory */
64     int    buffer; /* buffered memory */
65     int    cached; /* cache memory */
66 } tDataSet;
67 
68 
69 /* global input variables */
70 ulong  warnS = 75; /* used virtual (=real+swap) memory */
71 char   warnU = '%';
72 ulong  critS = 85;
73 char   critU = '%';
74 
75 /*
76  * SNMP base OID
77  * UCD-SNMP-MIB::memTotalSwap.0 = 1.3.6.1.4.1.2021.4.3.0
78  * UCD-SNMP-MIB::memAvailSwap.0 = 1.3.6.1.4.1.2021.4.4.0
79  * UCD-SNMP-MIB::memTotalReal.0 = 1.3.6.1.4.1.2021.4.5.0
80  * UCD-SNMP-MIB::memAvailReal.0 = 1.3.6.1.4.1.2021.4.6.0
81  * UCD-SNMP-MIB::memTotalFree.0 = 1.3.6.1.4.1.2021.4.11.0
82  * UCD-SNMP-MIB::memShared.0    = 1.3.6.1.4.1.2021.4.13.0
83  * UCD-SNMP-MIB::memBuffer.0    = 1.3.6.1.4.1.2021.4.14.0
84  * UCD-SNMP-MIB::memCached.0    = 1.3.6.1.4.1.2021.4.15.0
85  */
86 oid baseOID[] = { 1, 3, 6, 1, 4, 1, 2021, 4 };
87 size_t baseOIDLen = 8;
88 
89 /* scan results */
90 tScanRes* scanRes = NULL;
91 int scanResLen = 0;
92 
93 /* results of the SNMP queries */
94 tDataSet v;
95 
96 
SetGlobals()97 void SetGlobals ()
98 {
99     /* progName is set by ReadArgs() */
100     srvName = "check_ucd_mem";
101     progVersion = "0.1";
102     helpIndexP = NULL;
103     helpThresP = "[-w WARN] [-c CRIT]";
104     helpPurpose = "Checks the memory usage of a u*ix computer.";
105     /* community is set by ReadArgs() */
106     /* commFile is set by ReadArgs() */
107 #if(WITH_RRD)
108     rrdStep = 1 * 60;
109     rrdHBeat = 3 * 60;
110 #endif /* WITH_RRD */
111     supportsPerfLog = TRUE;
112     hasIndexParam = FALSE;
113     hasAddInfParam = FALSE;
114 }
115 
HelpSpecificParams()116 void HelpSpecificParams ()
117 {
118     printf (
119     "-w, --warning INTEGER[%%kMG]\n"
120     "    Virtual (= swap + real) memory usage at which a warning is "
121     "generated.\n"
122     "    Default is %lu%c.\n", warnS, warnU
123     );
124     printf (
125     "\n"
126     "-c, --critical INTEGER[%%kMG]\n"
127     "    Virtual (= swap + real) memory usage at which a critical is "
128     "generated.\n"
129     "    Default is %lu%c.\n", critS, critU
130     );
131 }
132 
HelpExplain()133 void HelpExplain ()
134 {
135     printf (
136     "If the warning and critical parameters are given without unit, then the\n"
137     "unit Bytes is assumed. '%%', 'k', 'M' and 'G' are interpreted as\n"
138     "percent of the total space, Kilobytes (1024 Bytes), Megabytes\n"
139     "(1024*1024 Bytes) and Gigabytes (1024*1024*1024 Bytes) respectively.\n"
140     );
141 }
142 
HelpPerformanceData()143 void HelpPerformanceData ()
144 {
145     printf (
146     "Native performance data is provided in the format (all in one line):\n"
147     "<sTotal>;<sAvail>;<rTotal>;<rAvail>;<tTotal>;<tAvail>;<shared>;\n"
148     "<buffer>;<cached>;\n"
149     "where\n"
150     "    sTotal ... total swap space.\n"
151     "    sAvail ... available swap space.\n"
152     "    rTotal ... total real/physical memory.\n"
153     "    rAvail ... available real/physical memory.\n"
154     "    tTotal ... total memory.\n"
155     "    tAvail ... total available memory.\n"
156     "    shared ... shared memory.\n"
157     "    buffer ... buffered memory.\n"
158     "    cached ... cache memory.\n"
159     "\n"
160     );
161     printf (
162     "Nagios Plugins compatible performance data is provided in the format:\n"
163     "'swap space'=<sAvail>KB;;;0;<sTotal> "
164     "'real memory'=<rAvail>KB;;;0;<rTotal> "
165     "'available memory'=<tAvail>KB;<warn>;<crit>;0;<tTotal> "
166     "'shared memory'=<shared>KB "
167     "'buffered memory'=<buffer>KB "
168     "'cache memory'=<cached>KB\n"
169     "\n"
170     );
171 }
172 
CheckSpaceUnit(char * aUnit)173 char CheckSpaceUnit ( char* aUnit )
174 {
175     char ret = '1';
176     if      ( !strcmp ( aUnit, ""  ) ) ret = '1';
177     else if ( !strcmp ( aUnit, "k" ) ) ret = 'k';
178     else if ( !strcmp ( aUnit, "M" ) ) ret = 'M';
179     else if ( !strcmp ( aUnit, "%" ) ) ret = '%';
180     else Usage ( "invalid space unit" );
181     return ( ret );
182 }
183 
ChkOptSpecificParams(int argc,char ** argv,int * i)184 int ChkOptSpecificParams ( int argc, char** argv, int* i )
185 {
186     int ret = TRUE;
187 
188     if (        !strcmp ( argv [(*i)], "-w" )
189             ||  !strcmp ( argv [(*i)], "--warning" ) )
190     {
191         (*i)++;
192         if ( (*i) < argc )
193         {
194             char *tail = argv [(*i)];
195             errno = 0;
196             warnS = strtoul ( argv [(*i)++], &tail, 0 );
197             if ( errno ) Usage ( "Invalid 'warn' parameter" );
198             warnU = CheckSpaceUnit ( tail );
199         } else Usage ( "Missing 'warn' parameter(s)" );
200     } else if ( !strcmp ( argv [(*i)], "-c" )
201             ||  !strcmp ( argv [(*i)], "--critical" ) )
202     {
203         (*i)++;
204         if ( (*i) < argc )
205         {
206             char *tail = argv [(*i)];
207             errno = 0;
208             critS = strtoul ( argv [(*i)++], &tail, 0 );
209             if ( errno ) Usage ( "Invalid 'crit' parameter" );
210             critU = CheckSpaceUnit ( tail );
211         } else Usage ( "Missing 'crit' parameter(s)" );
212     } else ret = FALSE;
213     return ( ret );
214 }
215 
SnmpWalkHandleVariable(netsnmp_variable_list * aVar)216 void SnmpWalkHandleVariable ( netsnmp_variable_list* aVar )
217 {
218     if ( aVar->name_length == 10 )
219     {
220         if ( OidCmp ( aVar->name, baseOID, baseOIDLen ) == 0 )
221         {
222             if ( aVar->name [9] == 0 )
223             {
224                 int typeOK = FALSE;
225                 int valOK = FALSE;
226 
227                 switch ( aVar->name [8] )
228                 {
229                     case 3: /* memTotalSwap */
230                         scanResLen = 1;
231                         scanRes = realloc ( scanRes,
232                                 sizeof ( tScanRes ) * scanResLen );
233                         if ( scanRes == NULL ) ErrorMalloc ();
234                         typeOK = ( aVar->type == ASN_INTEGER );
235                         valOK = ( *(aVar->val.integer) > 0 );
236                         scanRes [0].v3 = ( typeOK && valOK );
237                         scanRes [0].v4 = FALSE;
238                         scanRes [0].v5 = FALSE;
239                         scanRes [0].v6 = FALSE;
240                         scanRes [0].v11 = FALSE;
241                         scanRes [0].v13 = FALSE;
242                         scanRes [0].v14 = FALSE;
243                         scanRes [0].v15 = FALSE;
244                     break;
245                     case 4: /* memAvailSwap */
246                         typeOK = ( aVar->type == ASN_INTEGER );
247                         valOK = ( *(aVar->val.integer) > 0 );
248                         scanRes [0].v4 = ( typeOK && valOK );
249                     break;
250                     case 5: /* memTotalReal */
251                         typeOK = ( aVar->type == ASN_INTEGER );
252                         valOK = ( *(aVar->val.integer) > 0 );
253                         scanRes [0].v5 = ( typeOK && valOK );
254                     break;
255                     case 6: /* memAvailReal */
256                         typeOK = ( aVar->type == ASN_INTEGER );
257                         valOK = ( *(aVar->val.integer) > 0 );
258                         scanRes [0].v6 = ( typeOK && valOK );
259                     break;
260                     case 11: /* memTotalFree */
261                         typeOK = ( aVar->type == ASN_INTEGER );
262                         valOK = ( *(aVar->val.integer) > 0 );
263                         scanRes [0].v11 = ( typeOK && valOK );
264                     break;
265                     case 13: /* memShared */
266                         typeOK = ( aVar->type == ASN_INTEGER );
267                         valOK = ( *(aVar->val.integer) > 0 );
268                         scanRes [0].v13 = ( typeOK && valOK );
269                     break;
270                     case 14: /* memBuffer */
271                         typeOK = ( aVar->type == ASN_INTEGER );
272                         valOK = ( *(aVar->val.integer) > 0 );
273                         scanRes [0].v14 = ( typeOK && valOK );
274                     break;
275                     case 15: /* memCached */
276                         typeOK = ( aVar->type == ASN_INTEGER );
277                         valOK = ( *(aVar->val.integer) > 0 );
278                         scanRes [0].v15 = ( typeOK && valOK );
279                     break;
280                     default:
281                         /* don't care */
282                     break;
283                 }
284             }
285             else Log ( LOG_CRIT, "Unexpected index (!= 0) while scanning" );
286         } else Log ( LOG_CRIT, "Unexpected OID while scanning services" );
287     } else Log ( LOG_CRIT, "Wrong length while scanning services" );
288 }
289 
ScanServices()290 int ScanServices ()
291 {
292     int i;
293     int retVal = STATE_UNKNOWN;
294 
295     SnmpWalk ( baseOID, baseOIDLen );
296     for ( i = 0; i < scanResLen; i++ )
297     {
298         if (    scanRes [i].v3  && scanRes [i].v4  && scanRes [i].v5  &&
299                 scanRes [i].v6  && scanRes [i].v11 && scanRes [i].v13 &&
300                 scanRes [i].v14 && scanRes [i].v15 )
301         {
302             retVal = STATE_OK;
303             printf ( "OK\n" );
304         }
305     }
306     if ( retVal == STATE_UNKNOWN ) printf ( "FAILED\n" );
307     return retVal;
308 }
309 
ReadVals()310 void ReadVals ()
311 {
312     struct snmp_session sess1;
313     struct snmp_session* sess2;
314     oid o_sTotal [10];
315     oid o_sAvail [10];
316     oid o_rTotal [10];
317     oid o_rAvail [10];
318     oid o_tAvail [10];
319     oid o_shared [10];
320     oid o_buffer [10];
321     oid o_cached [10];
322     size_t oidLen;
323 
324     OidCpy ( o_sTotal,  &oidLen, baseOID, &baseOIDLen );
325     OidCpy ( o_sAvail,  &oidLen, baseOID, &baseOIDLen );
326     OidCpy ( o_rTotal,  &oidLen, baseOID, &baseOIDLen );
327     OidCpy ( o_rAvail,  &oidLen, baseOID, &baseOIDLen );
328     OidCpy ( o_tAvail,  &oidLen, baseOID, &baseOIDLen );
329     OidCpy ( o_shared,  &oidLen, baseOID, &baseOIDLen );
330     OidCpy ( o_buffer,  &oidLen, baseOID, &baseOIDLen );
331     OidCpy ( o_cached,  &oidLen, baseOID, &baseOIDLen );
332     o_sTotal [8] =  3; o_sTotal [9] = 0;
333     o_sAvail [8] =  4; o_sAvail [9] = 0;
334     o_rTotal [8] =  5; o_rTotal [9] = 0;
335     o_rAvail [8] =  6; o_rAvail [9] = 0;
336     o_tAvail [8] = 11; o_tAvail [9] = 0;
337     o_shared [8] = 13; o_shared [9] = 0;
338     o_buffer [8] = 14; o_buffer [9] = 0;
339     o_cached [8] = 15; o_cached [9] = 0;
340     oidLen = 10;
341     ConfigureSession1 ( &sess1 );
342     sess2 = snmp_open ( &sess1 );
343     if ( sess2 == NULL ) Error ( LOG_ERR, "Could not open session!" );
344     v.sTotal = ReadInteger ( sess2, o_sTotal, oidLen );
345     v.sAvail = ReadInteger ( sess2, o_sAvail, oidLen );
346     v.rTotal = ReadInteger ( sess2, o_rTotal, oidLen );
347     v.rAvail = ReadInteger ( sess2, o_rAvail, oidLen );
348     v.tAvail = ReadInteger ( sess2, o_tAvail, oidLen );
349     v.shared = ReadInteger ( sess2, o_shared, oidLen );
350     v.buffer = ReadInteger ( sess2, o_buffer, oidLen );
351     v.cached = ReadInteger ( sess2, o_cached, oidLen );
352     free ( sess1.peername );
353     free ( sess1.community );
354     snmp_close_sessions ();
355 }
356 
357 
358 #if(WITH_RRD)
CreateDataFile(const char * aRRDFPath)359 void CreateDataFile ( const char* aRRDFPath )
360 {
361     int i = 0;
362     char* params[1024]; /* Now that should be enough! */
363     params [i++] = StrDup ( "JUNK" );
364     params [i++] = StrDup ( aRRDFPath );
365     params [i++] = StrDup ( "-s" );
366     params [i++] = IntToStr ( rrdStep );
367     params [i++] = CreateDSStr ( "sTotal", GAUGE, rrdHBeat, "0", "U" );
368     params [i++] = CreateDSStr ( "sAvail", GAUGE, rrdHBeat, "0", "U" );
369     params [i++] = CreateDSStr ( "rTotal", GAUGE, rrdHBeat, "0", "U" );
370     params [i++] = CreateDSStr ( "rAvail", GAUGE, rrdHBeat, "0", "U" );
371     params [i++] = CreateDSStr ( "tAvail", GAUGE, rrdHBeat, "0", "U" );
372     params [i++] = CreateDSStr ( "shared", GAUGE, rrdHBeat, "0", "U" );
373     params [i++] = CreateDSStr ( "buffer", GAUGE, rrdHBeat, "0", "U" );
374     params [i++] = CreateDSStr ( "cached", GAUGE, rrdHBeat, "0", "U" );
375     params [i++] = RRA_MAX_25H_5M;
376     params [i++] = RRA_AVG_25H_5M;
377     params [i++] = RRA_MAX_8D_15M;
378     params [i++] = RRA_AVG_8D_15M;
379     params [i++] = RRA_MAX_32D_1H;
380     params [i++] = RRA_AVG_32D_1H;
381     params [i++] = RRA_MAX_367D_4H;
382     params [i++] = RRA_AVG_367D_4H;
383     RRDCreate ( i, params, aRRDFPath );
384     while ( i > 0 ) free ( params [--i] );
385 }
386 
ParseData(const char * aData)387 void ParseData ( const char* aData )
388 {
389     int chk;
390     int junk;
391 
392     chk = sscanf ( aData, "%i;%i;%i;%i;%i;%i;%i;%i;%i",
393             &(v.sTotal), &(v.sAvail), &(v.rTotal), &(v.rAvail),
394             &(junk),
395             &(v.tAvail), &(v.shared), &(v.buffer), &(v.cached) );
396     if ( chk != 8 )
397     {
398         char msg[1024];
399         snprintf ( msg, 1024,
400                 "Could not parse performance data: %s.\n", aData );
401         Error ( LOG_ERR, msg );
402     }
403 }
404 
WriteData(const char * aRRDFPath)405 void WriteData ( const char* aRRDFPath )
406 {
407     int i = 0;
408     char* params[1024]; /* Now that should be enough! */
409     char* ts     = UIntToStr   ( GetTimestamp () );
410     char* sTotal = IntToStr    ( v.sTotal );
411     char* sAvail = IntToStr    ( v.sAvail );
412     char* rTotal = IntToStr    ( v.rTotal );
413     char* rAvail = IntToStr    ( v.rAvail );
414     char* tAvail = IntToStr    ( v.tAvail );
415     char* shared = IntToStr    ( v.shared );
416     char* buffer = IntToStr    ( v.buffer );
417     char* cached = IntToStr    ( v.cached );
418 
419     params [i++] = StrDup ( "JUNK" );
420     params [i++] = StrDup ( aRRDFPath );
421     params [i++] = StrDup ( "-t" );
422     params [i++] = StrDup (
423             "sTotal:sAvail:rTotal:rAvail:"
424             "tAvail:shared:buffer:cached" );
425     params [i++] = StrConcat ( 17, ts, ":",
426             sTotal, ":", sAvail, ":", rTotal, ":", rAvail, ":",
427             tAvail, ":", shared, ":", buffer, ":", cached  );
428     RRDUpdate ( i, params, aRRDFPath );
429     while ( i > 0 ) free ( params [--i] );
430     free ( cached );
431     free ( buffer );
432     free ( shared );
433     free ( tAvail );
434     free ( rAvail );
435     free ( rTotal );
436     free ( sAvail );
437     free ( sTotal );
438     free ( ts );
439 }
440 
PlotDataReal(tFN * aFN,int aTiming,int aNow)441 void PlotDataReal ( tFN* aFN, int aTiming, int aNow )
442 {
443     tPP* pp = PPInit ();
444     int i = 0;
445     char* title = NULL;
446     char* vLabel = "[%]";
447     char* params[1024]; /* Now that should be enough! */
448 
449     FNSetPNGData ( aFN, "real", aTiming );
450     PPAddPlot ( pp, "used",   "%", FALSE );
451     PPAddPlot ( pp, "shared", "%", TRUE );
452     PPAddPlot ( pp, "buffer", "%", TRUE );
453     PPAddPlot ( pp, "cached", "%", TRUE );
454     PPAddPlot ( pp, "tAvail", "%", TRUE );
455     title = StrConcat ( 2, hostName, " real memory" );
456     i = PlotStdParams ( params, aFN, title, vLabel,
457             aTiming, aNow - rrdHBeat, 1000, PLOT_SI_NONE, 0, 100, FALSE );
458     params [i++] = CreateDEF ( "sizeMR", aFN, "rTotal",  MAX );
459     params [i++] = CreateDEF ( "sizeAR", aFN, "rTotal",  AVG );
460     params [i++] = CreateDEF ( "sharMR", aFN, "shared",  MAX );
461     params [i++] = CreateDEF ( "sharAR", aFN, "shared",  AVG );
462     params [i++] = CreateDEF ( "buffMR", aFN, "buffer",  MAX );
463     params [i++] = CreateDEF ( "buffAR", aFN, "buffer",  AVG );
464     params [i++] = CreateDEF ( "cachMR", aFN, "cached",  MAX );
465     params [i++] = CreateDEF ( "cachAR", aFN, "cached",  AVG );
466     params [i++] = CreateDEF ( "freeMR", aFN, "rAvail",  MAX );
467     params [i++] = CreateDEF ( "freeAR", aFN, "rAvail",  AVG );
468     params [i++] = StrDup ( "CDEF:usedMR=sizeMR,sharMR,-,buffMR,-,cachMR,-,freeMR,-" );
469     params [i++] = StrDup ( "CDEF:usedAR=sizeAR,sharAR,-,buffAR,-,cachAR,-,freeAR,-" );
470     params [i++] = StrDup ( "CDEF:usedM=usedMR,sizeMR,/,100,*" );
471     params [i++] = StrDup ( "CDEF:usedA=usedAR,sizeAR,/,100,*" );
472     params [i++] = StrDup ( "CDEF:sharM=sharMR,sizeMR,/,100,*" );
473     params [i++] = StrDup ( "CDEF:sharA=sharAR,sizeAR,/,100,*" );
474     params [i++] = StrDup ( "CDEF:buffM=buffMR,sizeMR,/,100,*" );
475     params [i++] = StrDup ( "CDEF:buffA=buffAR,sizeAR,/,100,*" );
476     params [i++] = StrDup ( "CDEF:cachM=cachMR,sizeMR,/,100,*" );
477     params [i++] = StrDup ( "CDEF:cachA=cachAR,sizeAR,/,100,*" );
478     params [i++] = StrDup ( "CDEF:freeM=freeMR,sizeMR,/,100,*" );
479     params [i++] = StrDup ( "CDEF:freeA=freeAR,sizeAR,/,100,*" );
480     params [i++] = CreatePlot ( PLOT_AREA,  "usedM", C_LOAD3_MAX,  pp, 0, MAX, FALSE );
481     params [i++] = CreatePlot ( PLOT_STACK, "sharM", C_THRU_MAX,   pp, 1, MAX, FALSE );
482     params [i++] = CreatePlot ( PLOT_STACK, "buffM", C_USAGE2_MAX, pp, 2, MAX, TRUE  );
483     params [i++] = CreatePlot ( PLOT_STACK, "cachM", C_LOAD1_MAX,  pp, 3, MAX, FALSE );
484     params [i++] = CreatePlot ( PLOT_STACK, "freeM", C_FREE_MAX,   pp, 4, MAX, TRUE  );
485     params [i++] = CreatePlot ( PLOT_LINE3, "usedA", C_LOAD3_AVG,  pp, 0, AVG, FALSE );
486     params [i++] = CreatePlot ( PLOT_STACK, "sharA", C_THRU_AVG,   pp, 1, AVG, FALSE );
487     params [i++] = CreatePlot ( PLOT_STACK, "buffA", C_USAGE2_AVG, pp, 2, AVG, TRUE  );
488     params [i++] = CreatePlot ( PLOT_STACK, "cachA", C_LOAD1_AVG,  pp, 3, AVG, FALSE );
489     params [i++] = CreatePlot ( PLOT_STACK, "freeA", C_FREE_AVG,   pp, 4, AVG, TRUE  );
490     i = PlotPrintParams ( i, params, pp, 0, "usedA", "usedA", "usedM", "usedM", "%5.1lf" );
491     i = PlotPrintParams ( i, params, pp, 1, "sharA", "sharA", "sharM", "sharM", "%5.1lf" );
492     i = PlotPrintParams ( i, params, pp, 2, "buffA", "buffA", "buffM", "buffM", "%5.1lf" );
493     i = PlotPrintParams ( i, params, pp, 3, "cachA", "cachA", "cachM", "cachM", "%5.1lf" );
494     i = PlotPrintParams ( i, params, pp, 4, "freeA", "freeA", "freeM", "freeM", "%5.1lf" );
495     RRDGraph ( i, params, aFN, pp );
496     while ( i > 0 ) free ( params [--i] );
497     free ( title );
498     PPDone ( pp );
499     FNUnsetPNGData ( aFN );
500 }
501 
PlotDataSwap(tFN * aFN,int aTiming,int aNow)502 void PlotDataSwap ( tFN* aFN, int aTiming, int aNow )
503 {
504     tPP* pp = PPInit ();
505     int i = 0;
506     char* title = NULL;
507     char* vLabel = "[%]";
508     char* params[1024]; /* Now that should be enough! */
509 
510     FNSetPNGData ( aFN, "swap", aTiming );
511     PPAddPlot ( pp, "used", "%", FALSE );
512     PPAddPlot ( pp, "free", "%", TRUE );
513     title = StrConcat ( 2, hostName, " swap memory" );
514     i = PlotStdParams ( params, aFN, title, vLabel,
515             aTiming, aNow - rrdHBeat, 1000, PLOT_SI_NONE, 0, 100, FALSE );
516     params [i++] = CreateDEF ( "sizeMR", aFN, "sTotal", MAX );
517     params [i++] = CreateDEF ( "sizeAR", aFN, "sTotal", AVG );
518     params [i++] = CreateDEF ( "freeMR", aFN, "sAvail", MAX );
519     params [i++] = CreateDEF ( "freeAR", aFN, "sAvail", AVG );
520     params [i++] = StrDup ( "CDEF:usedMR=sizeMR,freeMR,-" );
521     params [i++] = StrDup ( "CDEF:usedAR=sizeAR,freeAR,-" );
522     params [i++] = StrDup ( "CDEF:usedM=usedMR,sizeMR,/,100,*" );
523     params [i++] = StrDup ( "CDEF:usedA=usedAR,sizeAR,/,100,*" );
524     params [i++] = StrDup ( "CDEF:freeM=freeMR,sizeMR,/,100,*" );
525     params [i++] = StrDup ( "CDEF:freeA=freeAR,sizeAR,/,100,*" );
526     params [i++] = CreatePlot ( PLOT_AREA,  "usedM", C_USAGE1_MAX, pp, 0, MAX, FALSE );
527     params [i++] = CreatePlot ( PLOT_STACK, "freeM", C_FREE_MAX,   pp, 1, MAX, TRUE  );
528     params [i++] = CreatePlot ( PLOT_LINE2, "usedA", C_USAGE1_AVG, pp, 0, AVG, FALSE );
529     params [i++] = CreatePlot ( PLOT_STACK, "freeA", C_FREE_AVG,   pp, 1, AVG, TRUE );
530     i = PlotPrintParams ( i, params, pp, 0, "usedA", "usedA", "usedM", "usedM", "%5.1lf" );
531     i = PlotPrintParams ( i, params, pp, 1, "freeA", "freeA", "freeM", "freeM", "%5.1lf" );
532     RRDGraph ( i, params, aFN, pp );
533     while ( i > 0 ) free ( params [--i] );
534     free ( title );
535     PPDone ( pp );
536     FNUnsetPNGData ( aFN );
537 }
538 
PlotPerfData()539 void PlotPerfData ()
540 {
541     int now = time ( NULL );
542     tFN* fn = FNInit ();
543 
544     PlotDataReal ( fn, PLOT_6H_1M,   now );
545     PlotDataSwap ( fn, PLOT_6H_1M,   now );
546     PlotDataReal ( fn, PLOT_24H_5M,  now );
547     PlotDataSwap ( fn, PLOT_24H_5M,  now );
548     PlotDataReal ( fn, PLOT_7D_15M,  now );
549     PlotDataSwap ( fn, PLOT_7D_15M,  now );
550     PlotDataReal ( fn, PLOT_31D_60M, now );
551     PlotDataSwap ( fn, PLOT_31D_60M, now );
552     PlotDataReal ( fn, PLOT_366D_4H, now );
553     PlotDataSwap ( fn, PLOT_366D_4H, now );
554     FNDone ( fn );
555 }
556 #endif /* WITH_RRD */
557 
LevelToKB(char * aWhat,int aLevel,char aUnit,int aSize)558 int LevelToKB ( char* aWhat, int aLevel, char aUnit, int aSize )
559 {
560     double retVal = 0.0;
561     double level = (double) aLevel;
562 
563     switch ( aUnit )
564     {
565         case '1': retVal = level / 1024 ;           break;
566         case 'k': retVal = level;                   break;
567         case 'M': retVal = level * 1024;            break;
568         case 'G': retVal = level * 1024 * 1024;     break;
569         case '%': retVal = ( level * aSize ) / 100; break;
570         default:
571         {
572             Error ( LOG_ERR, "An invalid level slipped through!" );
573         }
574         break;
575     }
576     return ( retVal );
577 }
578 
CheckData()579 int CheckData ()
580 {
581     int retVal = STATE_OK;
582     int tTotal;
583     int tUsed;
584     int tWarn;
585     int tCrit;
586     int rUsed;
587     int sUsed;
588     double tUsedP;
589     double rUsedP;
590     double sUsedP;
591 
592 
593     ReadVals ();
594     /* calculate everything in Kibibytes */
595     tTotal = v.sTotal + v.rTotal;
596     tUsed = tTotal - v.tAvail;
597     tWarn = LevelToKB ( "warning level",  warnS, warnU, tTotal );
598     tCrit = LevelToKB ( "critical level", critS, critU, tTotal );
599     rUsed = v.rTotal - v.rAvail;
600     sUsed = v.sTotal - v.sAvail;
601     tUsedP = ( ( (double) tUsed ) * 100.0 ) / (double) tTotal;
602     sUsedP = ( ( (double) sUsed ) * 100.0 ) / (double) v.sTotal;
603     rUsedP = ( ( (double) rUsed ) * 100.0 ) / (double) v.rTotal;
604     if ( tWarn < tUsed ) retVal = MAXIMUM ( retVal, STATE_WARNING );
605     if ( tCrit < tUsed ) retVal = MAXIMUM ( retVal, STATE_CRITICAL );
606     PrintExit ( retVal );
607     printf ( " - available/total real: %i/%iKB (%3.1f%%), swap: %i/%iKB (%3.1f%%)",
608             v.rAvail, v.rTotal, rUsedP, v.sAvail, v.sTotal, sUsedP );
609     if ( npPerfData )
610     {
611         printf ( "|'swap space'=%iKB;;;0;%i",      v.sAvail, v.sTotal );
612         printf ( " 'real memory'=%iKB;;;0;%i",     v.rAvail, v.rTotal );
613         printf ( " 'free memory'=%iKB;%i;%i;0;%i",
614                 v.tAvail, tWarn, tCrit, tTotal );
615         printf ( " 'shared memory'=%iKB",          v.shared );
616         printf ( " 'buffered memory'=%iKB",        v.buffer );
617         printf ( " 'cache memory'=%iKB\n",         v.cached );
618     }
619     else
620     {
621         printf ( "|%i;%i;%i;%i;%i;%i;%i;%i;%i\n",
622                 v.sTotal, v.sAvail, v.rTotal, v.rAvail,
623                 tTotal,   v.tAvail, v.shared, v.buffer, v.cached );
624     }
625     return ( retVal );
626 }
627 
main(int argc,char ** argv)628 int main ( int argc, char** argv )
629 {
630     int retVal = STATE_OK;
631 
632     SetGlobals ();
633     ReadArgs ( argc, argv );
634     if ( scanServices ) retVal = ScanServices ();
635     else
636     {
637         if ( checkData ) retVal = CheckData ();
638 #if(WITH_RRD)
639         if ( logPerfData ) LogPerfData ();
640         if ( plotPerfData ) PlotPerfData ();
641 #endif /* WITH_RRD */
642     }
643     if ( hostName != NULL ) free ( hostName );
644     if ( hostAddr != NULL ) free ( hostAddr );
645     if ( progName != NULL ) free ( progName );
646     return ( retVal );
647 }
648