1 /*
2  * File:      check_cpq_phydrv.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 typedef struct
43 {
44     int index;   /* controller index */
45     int pDrv;    /* physical drive index */
46     int v5;      /* found cpqDaPhyDrvBay */
47     int v6;      /* found cpqDaPhyDrvStatus */
48     int v9;      /* found cpqDaPhyDrvRefHours */
49     int v10;     /* found cpqDaPhyDrvHReads */
50     int v11;     /* found cpqDaPhyDrvReads */
51     int v12;     /* found cpqDaPhyDrvHWrites */
52     int v13;     /* found cpqDaPhyDrvWrites */
53     int v16;     /* found cpqDaPhyDrvHardReadErrs */
54     int v17;     /* found cpqDaPhyDrvRecvReadErrs */
55     int v18;     /* found cpqDaPhyDrvHardWriteErrs */
56     int v19;     /* found cpqDaPhyDrvRecvWriteErrs */
57     int v35;     /* found cpqDaPhyDrvThreshPassed */
58     int v36;     /* found cpqDaPhyDrvHasMonInfo and is OK */
59     int v37;     /* found cpqDaPhyDrvCondition */
60     int v49;     /* found cpqDaPhyDrvPlacement */
61     int v51;     /* found cpqDaPhyDrvSerialNum */
62     int v57;     /* found cpqDaPhyDrvSmartStatus */
63     int place;   /* placement */
64     char* ser;   /* serial number */
65     int bay;     /* bay */
66 } tScanRes;
67 
68 /* data type for storing data */
69 typedef struct
70 {
71     int      bay;   /* bay the drive is in */
72     int      stat;  /* status of the drive */
73     int      cond;  /* condition of the drive */
74     int      smart; /* smart status of the drive */
75     int      thres; /* thresholds status of the drive */
76     uint     hours; /* operating hours of the drive */
77     uint     read;  /* reads from the drive */
78     uint     writ;  /* writes to the drive */
79     uint     haRd;  /* hard read errors */
80     uint     reRd;  /* recoverable read errors */
81     uint     haWr;  /* hard write errors */
82     uint     reWr;  /* recoverable write errors */
83 } tDataSet;
84 
85 /* global input variables */
86 int pDrv;
87 int isPDrvSet  = FALSE;
88 
89 /*
90  * SNMP base OID
91  * CPQIDA-MIB::cpqDaPhyDrvBay.CTRL.PDRV
92  * = 1.3.6.1.4.1.232.3.2.5.1.1.5.CTRL.PDRV
93  * CPQIDA-MIB::cpqDaPhyDrvStatus.CTRL.PDRV
94  * = 1.3.6.1.4.1.232.3.2.5.1.1.6.CTRL.PDRV
95  * CPQIDA-MIB::cpqDaPhyDrvCondition.CTRL.PDRV
96  * = 1.3.6.1.4.1.232.3.2.5.1.1.37.CTRL.PDRV
97  * CPQIDA-MIB::cpqDaPhyDrvSmartStatus.CTRL.PDRV
98  * = 1.3.6.1.4.1.232.3.2.5.1.1.57.CTRL.PDRV
99  * CPQIDA-MIB::cpqDaPhyDrvThreshPassed.CTRL.PDRV
100  * = 1.3.6.1.4.1.232.3.2.5.1.1.35.CTRL.PDRV
101  * CPQIDA-MIB::cpqDaPhyDrvRefHours.CTRL.PDRV
102  * = 1.3.6.1.4.1.232.3.2.5.1.1.9.CTRL.PDRV
103  * CPQIDA-MIB::cpqDaPhyDrvHReads.CTRL.PDRV
104  * = 1.3.6.1.4.1.232.3.2.5.1.1.10.CTRL.PDRV
105  * CPQIDA-MIB::cpqDaPhyDrvReads.CTRL.PDRV
106  * = 1.3.6.1.4.1.232.3.2.5.1.1.11.CTRL.PDRV
107  * CPQIDA-MIB::cpqDaPhyDrvHWrites.CTRL.PDRV
108  * = 1.3.6.1.4.1.232.3.2.5.1.1.12.CTRL.PDRV
109  * CPQIDA-MIB::cpqDaPhyDrvWrites.CTRL.PDRV
110  * = 1.3.6.1.4.1.232.3.2.5.1.1.13.CTRL.PDRV
111  * CPQIDA-MIB::cpqDaPhyDrvHardReadErrs.CTRL.PDRV
112  * = 1.3.6.1.4.1.232.3.2.5.1.1.16.CTRL.PDRV
113  * CPQIDA-MIB::cpqDaPhyDrvRecvReadErrs.CTRL.PDRV
114  * = 1.3.6.1.4.1.232.3.2.5.1.1.17.CTRL.PDRV
115  * CPQIDA-MIB::cpqDaPhyDrvHardWriteErrs.CTRL.PDRV
116  * = 1.3.6.1.4.1.232.3.2.5.1.1.18.CTRL.PDRV
117  * CPQIDA-MIB::cpqDaPhyDrvRecvWriteErrs.CTRL.PDRV
118  * = 1.3.6.1.4.1.232.3.2.5.1.1.19.CTRL.PDRV
119  * CPQIDA-MIB:cpqDaPhyDrvPlacement:.CTRL.PDRV
120  * = 1.3.6.1.4.1.232.3.2.5.1.1.49.CTRL.PDRV
121  * CPQIDA-MIB:cpqDaPhyDrvSerialNum:.CTRL.PDRV
122  * = 1.3.6.1.4.1.232.3.2.5.1.1.51.CTRL.PDRV
123  */
124 oid baseOID [] = { 1, 3, 6, 1, 4, 1, 232, 3, 2, 5, 1, 1 };
125 size_t baseOIDLen = 12;
126 
127 /* scan results */
128 tScanRes* scanRes = NULL;
129 int scanResLen = 0;
130 
131 /* results of the SNMP queries */
132 tDataSet v;
133 
134 
SetGlobals()135 void SetGlobals ()
136 {
137     /* progName is set by ReadArgs() */
138     srvName = "check_cpq_phydrv";
139     progVersion = "0.8";
140     helpIndexP = "-i INDEX -d DRIVE";
141     helpThresP = NULL;
142     helpPurpose =
143             "Checks the state of a physical drive connected to a Compaq\n"
144             "Intelligent Drive Array Controller.";
145     /* community is set by ReadArgs() */
146     /* commFile is set by ReadArgs() */
147 #if(WITH_RRD)
148     rrdStep = 5 * 60;
149     rrdHBeat = 11 * 60;
150 #endif /* WITH_RRD */
151     supportsPerfLog = TRUE;
152     hasIndexParam = TRUE;
153     hasAddInfParam = TRUE;
154 }
155 
HelpSpecificParams()156 void HelpSpecificParams ()
157 {
158     printf (
159     "-i, --index INTEGER\n"
160     "    Index of the controller to which the drive which should be checked\n"
161     "    is connected.\n"
162     "\n"
163     "-d, --drive INTEGER\n"
164     "    Index of the physical drive.\n"
165     "\n"
166     );
167 }
168 
HelpExplain()169 void HelpExplain ()
170 {
171     printf (
172     "The plugin returns the overall state of the physical drive."
173     "\n"
174     );
175 }
176 
HelpPerformanceData()177 void HelpPerformanceData ()
178 {
179     printf (
180     "Native performance data is provided in the format:\n"
181     "<addInf>;<read>;<writ>;<haRd>;<reRd>;<haWr>;<reRw>\n"
182     "where\n"
183     "    addInf ... additional information.\n"
184     "    read   ... Sectors read\n"
185     "    writ   ... Sectors written\n"
186     "    haRd   ... Hard read errors\n"
187     "    reRd   ... Recovered read errors\n"
188     "    haWr   ... Hard write errors\n"
189     "    reWr   ... Recovered write errors\n"
190     "\n"
191     );
192     printf (
193     "Nagios Plugins compatible performance data is provided in the format:\n"
194     "'sectors read'=<read>c "
195     "'sectors written'=<writ>c "
196     "'hard read errors'=<haRd>c "
197     "'recovered read errors'=<reRd>c "
198     "'hard write errors'=<haWr>c "
199     "'recovered write errors'=<reRw>c\n"
200     "\n"
201     );
202     printf (
203     "For more information about those counters see CPQIDA-MIB.txt\n"
204     "\n"
205     );
206 }
207 
ChkOptSpecificParams(int argc,char ** argv,int * i)208 int ChkOptSpecificParams ( int argc, char** argv, int* i )
209 {
210     int ret = TRUE;
211 
212     if (        !strcmp ( argv [(*i)], "-d" )
213             ||  !strcmp ( argv [(*i)], "--drive" ) )
214     {
215         isPDrvSet = TRUE;
216         (*i)++;
217         if ( (*i) < argc )
218         {
219             char *tail = argv [(*i)];
220             errno = 0;
221             pDrv = strtoul ( argv [(*i)++], &tail, 0 );
222             if ( errno || *tail ) Usage ( "Invalid 'drive' parameter" );
223         }
224         else Usage ( "Missing 'drive' parameter(s)" );
225     } else ret = FALSE;
226     return ( ret );
227 }
228 
ScanResIndex(int aIndex,int aPDrv)229 int ScanResIndex ( int aIndex, int aPDrv )
230 {
231     int retVal = 0;
232     int found = FALSE;
233 
234     while ( ( retVal < scanResLen ) && !found )
235     {
236         found = ( scanRes [retVal].index == aIndex )
237                 && ( scanRes [retVal].pDrv == aPDrv );
238         if ( !found ) retVal++;
239     }
240     if ( !found ) retVal = -1;
241     return retVal;
242 }
243 
SnmpWalkHandleVariable(netsnmp_variable_list * aVar)244 void SnmpWalkHandleVariable ( netsnmp_variable_list* aVar )
245 {
246     if ( aVar->name_length == 15 )
247     {
248         if ( OidCmp ( aVar->name, baseOID, baseOIDLen ) == 0 )
249         {
250             int index;
251 
252             switch ( aVar->name [12] )
253             {
254                 case 2: /* cpqDaPhyDrvIndex */
255                     index = scanResLen;
256                     scanResLen++;
257                     scanRes = realloc ( scanRes,
258                             sizeof ( tScanRes ) * scanResLen );
259                     if ( scanRes == NULL ) ErrorMalloc ();
260                     scanRes [index].index = aVar->name [13];
261                     scanRes [index].pDrv = aVar->name [14];
262                     scanRes [index].v5 = FALSE;
263                     scanRes [index].v6 = FALSE;
264                     scanRes [index].v9 = FALSE;
265                     scanRes [index].v11 = FALSE;
266                     scanRes [index].v13 = FALSE;
267                     scanRes [index].v16 = FALSE;
268                     scanRes [index].v17 = FALSE;
269                     scanRes [index].v18 = FALSE;
270                     scanRes [index].v19 = FALSE;
271                     scanRes [index].v35 = FALSE;
272                     scanRes [index].v36 = FALSE;
273                     scanRes [index].v37 = FALSE;
274                     scanRes [index].v57 = FALSE;
275                 break;
276                 case 5: /* cpqDaPhyDrvBay */
277                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
278                     scanRes [index].v5 = ( aVar->type == ASN_INTEGER );
279                     scanRes [index].bay = *(aVar->val.integer);
280                 break;
281                 case 6: /* cpqDaPhyDrvStatus */
282                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
283                     scanRes [index].v6 = ( aVar->type == ASN_INTEGER );
284                 break;
285                 case 9: /* cpqDaPhyDrvRefHours */
286                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
287                     scanRes [index].v9 = ( aVar->type == ASN_COUNTER );
288                 break;
289                 case 11: /* cpqDaPhyDrvReads */
290                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
291                     scanRes [index].v11 = ( aVar->type == ASN_COUNTER );
292                 break;
293                 case 13: /* cpqDaPhyDrvWrites */
294                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
295                     scanRes [index].v13 = ( aVar->type == ASN_COUNTER );
296                 break;
297                 case 16: /* cpqDaPhyDrvHardReadErrs */
298                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
299                     scanRes [index].v16 = ( aVar->type == ASN_COUNTER );
300                 break;
301                 case 17: /* cpqDaPhyDrvRecvReadErrs */
302                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
303                     scanRes [index].v17 = ( aVar->type == ASN_COUNTER );
304                 break;
305                 case 18: /* cpqDaPhyDrvHardWriteErrs */
306                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
307                     scanRes [index].v18 = ( aVar->type == ASN_COUNTER );
308                 break;
309                 case 19: /* cpqDaPhyDrvRecvWriteErrs */
310                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
311                     scanRes [index].v19 = ( aVar->type == ASN_COUNTER );
312                 break;
313                 case 35: /* cpqDaPhyDrvThreshPassed */
314                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
315                     scanRes [index].v35 = ( aVar->type == ASN_INTEGER );
316                 break;
317                 case 36: /* cpqDaPhyDrvHasMonInfo */
318                 {
319                     int typeOK = ( aVar->type == ASN_INTEGER );
320                     int valOK = ( *(aVar->val.integer) == 2 );
321 
322                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
323                     scanRes [index].v36 = ( typeOK && valOK );
324                 }
325                 break;
326                 case 37: /* cpqDaPhyDrvCondition */
327                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
328                     scanRes [index].v37 = ( aVar->type == ASN_INTEGER );
329                 break;
330                 case 49: /* cpqDaPhyDrvPlacement */
331                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
332                     scanRes [index].v49 = ( aVar->type == ASN_INTEGER );
333                     scanRes [index].place = *(aVar->val.integer);
334                 break;
335                 case 51: /* cpqDaPhyDrvSerialNum */
336                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
337                     scanRes [index].v51 = ( aVar->type == ASN_OCTET_STR );
338                     scanRes [index].ser = VarListStrDup ( aVar );
339                 break;
340                 case 57: /* cpqDaPhyDrvSmartStatus */
341                     index = ScanResIndex ( aVar->name [13], aVar->name [14] );
342                     scanRes [index].v57 = ( aVar->type == ASN_INTEGER );
343                 break;
344                 default:
345                     /* don't care */
346                 break;
347             }
348         } else Log ( LOG_CRIT, "Unexpected OID while scanning services" );
349     } else Log ( LOG_CRIT, "Wrong length while scanning services" );
350 }
351 
ScanServices()352 int ScanServices ()
353 {
354     int i;
355     int retVal = STATE_UNKNOWN;
356 
357     SnmpWalk ( baseOID, baseOIDLen );
358     for ( i = 0; i < scanResLen; i++ )
359     {
360         if (    scanRes [i].v5  && scanRes [i].v6  && scanRes [i].v9  &&
361                 scanRes [i].v11 && scanRes [i].v13 && scanRes [i].v16 &&
362                 scanRes [i].v17 && scanRes [i].v18 && scanRes [i].v19 &&
363                 scanRes [i].v35 && scanRes [i].v36 && scanRes [i].v37 &&
364                 scanRes [i].v49 && scanRes [i].v51 && scanRes [i].v57 )
365         {
366             char* place = NULL;
367 
368             switch ( scanRes[i].place )
369             {
370                 case  1: place = "other";    break;
371                 case  2: place = "int";      break;
372                 case  3: place = "ext";      break;
373                 default: place = "invalid";  break;
374             }
375             retVal = STATE_OK;
376             printf ( "OK index: %i ; drive: %i ; place: %s ; bay: %i",
377                     scanRes [i].index, scanRes [i].pDrv, place,
378                     scanRes [i].bay );
379             printf ( " ; ser: %s\n",
380                     scanRes [i].ser );
381         }
382     }
383     if ( retVal == STATE_UNKNOWN ) printf ( "FAILED\n" );
384     return retVal;
385 }
386 
ReadVals()387 void ReadVals ()
388 {
389     struct snmp_session sess1;
390     struct snmp_session* sess2;
391     oid o_bay   [15];
392     oid o_stat  [15];
393     oid o_cond  [15];
394     oid o_smart [15];
395     oid o_thres [15];
396     oid o_hours [15];
397     oid o_read  [15];
398     oid o_writ  [15];
399     oid o_haRd  [15];
400     oid o_reRd  [15];
401     oid o_haWr  [15];
402     oid o_reWr  [15];
403     size_t oidLen;
404 
405     OidCpy ( o_bay,   &oidLen, baseOID, &baseOIDLen );
406     OidCpy ( o_stat,  &oidLen, baseOID, &baseOIDLen );
407     OidCpy ( o_cond,  &oidLen, baseOID, &baseOIDLen );
408     OidCpy ( o_smart, &oidLen, baseOID, &baseOIDLen );
409     OidCpy ( o_thres, &oidLen, baseOID, &baseOIDLen );
410     OidCpy ( o_hours, &oidLen, baseOID, &baseOIDLen );
411     OidCpy ( o_read,  &oidLen, baseOID, &baseOIDLen );
412     OidCpy ( o_writ,  &oidLen, baseOID, &baseOIDLen );
413     OidCpy ( o_haRd,  &oidLen, baseOID, &baseOIDLen );
414     OidCpy ( o_reRd,  &oidLen, baseOID, &baseOIDLen );
415     OidCpy ( o_haWr,  &oidLen, baseOID, &baseOIDLen );
416     OidCpy ( o_reWr,  &oidLen, baseOID, &baseOIDLen );
417     o_bay   [12] =  5; o_bay   [13] = idx; o_bay   [14] = pDrv;
418     o_stat  [12] =  6; o_stat  [13] = idx; o_stat  [14] = pDrv;
419     o_cond  [12] = 37; o_cond  [13] = idx; o_cond  [14] = pDrv;
420     o_smart [12] = 57; o_smart [13] = idx; o_smart [14] = pDrv;
421     o_thres [12] = 35; o_thres [13] = idx; o_thres [14] = pDrv;
422     o_hours [12] =  9; o_hours [13] = idx; o_hours [14] = pDrv;
423     o_read  [12] = 11; o_read  [13] = idx; o_read  [14] = pDrv;
424     o_writ  [12] = 13; o_writ  [13] = idx; o_writ  [14] = pDrv;
425     o_haRd  [12] = 16; o_haRd  [13] = idx; o_haRd  [14] = pDrv;
426     o_reRd  [12] = 17; o_reRd  [13] = idx; o_reRd  [14] = pDrv;
427     o_haWr  [12] = 18; o_haWr  [13] = idx; o_haWr  [14] = pDrv;
428     o_reWr  [12] = 19; o_reWr  [13] = idx; o_reWr  [14] = pDrv;
429     oidLen = 15;
430     ConfigureSession1 ( &sess1 );
431     sess2 = snmp_open ( &sess1 );
432     if ( sess2 == NULL ) Error ( LOG_ERR, "Could not open session!" );
433     v.bay   = ReadInteger   ( sess2, o_bay,   oidLen );
434     v.stat  = ReadInteger   ( sess2, o_stat,  oidLen );
435     v.cond  = ReadInteger   ( sess2, o_cond,  oidLen );
436     v.smart = ReadInteger   ( sess2, o_smart, oidLen );
437     v.thres = ReadInteger   ( sess2, o_thres, oidLen );
438     v.hours = ReadCounter32 ( sess2, o_hours, oidLen );
439     v.read  = ReadCounter32 ( sess2, o_read,  oidLen );
440     v.writ  = ReadCounter32 ( sess2, o_writ,  oidLen );
441     v.haRd  = ReadCounter32 ( sess2, o_haRd,  oidLen );
442     v.reRd  = ReadCounter32 ( sess2, o_reRd,  oidLen );
443     v.haWr  = ReadCounter32 ( sess2, o_haWr,  oidLen );
444     v.reWr  = ReadCounter32 ( sess2, o_reWr,  oidLen );
445     free ( sess1.peername );
446     free ( sess1.community );
447     snmp_close_sessions ();
448 }
449 
450 #if(WITH_RRD)
CreateDataFile(const char * aRRDFPath)451 void CreateDataFile ( const char* aRRDFPath )
452 {
453     int i = 0;
454     char* params[1024]; /* Now that should be enough! */
455     params [i++] = StrDup ( "JUNK" );
456     params [i++] = StrDup ( aRRDFPath );
457     params [i++] = StrDup ( "-s" );
458     params [i++] = IntToStr ( rrdStep );
459     params [i++] = CreateDSStr ( "read", COUNTER, rrdHBeat, "0", "U" );
460     params [i++] = CreateDSStr ( "writ", COUNTER, rrdHBeat, "0", "U" );
461     params [i++] = CreateDSStr ( "haRd", COUNTER, rrdHBeat, "0", "U" );
462     params [i++] = CreateDSStr ( "reRd", COUNTER, rrdHBeat, "0", "U" );
463     params [i++] = CreateDSStr ( "haWr", COUNTER, rrdHBeat, "0", "U" );
464     params [i++] = CreateDSStr ( "reWr", COUNTER, rrdHBeat, "0", "U" );
465     params [i++] = RRA_MAX_25H_5M;
466     params [i++] = RRA_AVG_25H_5M;
467     params [i++] = RRA_MAX_8D_15M;
468     params [i++] = RRA_AVG_8D_15M;
469     params [i++] = RRA_MAX_32D_1H;
470     params [i++] = RRA_AVG_32D_1H;
471     params [i++] = RRA_MAX_367D_4H;
472     params [i++] = RRA_AVG_367D_4H;
473     RRDCreate ( i, params, aRRDFPath );
474     while ( i > 0 ) free ( params [--i] );
475 }
476 
ParseData(const char * aData)477 void ParseData ( const char* aData )
478 {
479     int chk;
480     char buf[1024];
481 
482     chk = sscanf ( aData, "%1023s;%u;%u;%u;%u;%u;%u", buf,
483             &(v.read), &(v.writ), &(v.haRd), &(v.reRd), &(v.haWr), &(v.reWr) );
484     if ( chk != 7 )
485     {
486         char msg[1024];
487         snprintf ( msg, 1024,
488                 "Could not parse performance data: %s.\n", aData );
489         Error ( LOG_ERR, msg );
490     }
491     addInf = StrDup ( buf );
492     v.bay = -1;
493     v.stat = -1;
494     v.cond = -1;
495     v.smart = -1;
496     v.thres = -1;
497 }
498 
WriteData(const char * aRRDFPath)499 void WriteData ( const char* aRRDFPath )
500 {
501     int i = 0;
502     char* params[1024]; /* Now that should be enough! */
503     char* ts     = UIntToStr   ( GetTimestamp () );
504     char* read   = UIntToStr   ( v.read );
505     char* writ   = UIntToStr   ( v.writ );
506     char* haRd   = UIntToStr   ( v.haRd );
507     char* reRd   = UIntToStr   ( v.reRd );
508     char* haWr   = UIntToStr   ( v.haWr );
509     char* reWr   = UIntToStr   ( v.reWr );
510 
511     params [i++] = StrDup ( "JUNK" );
512     params [i++] = StrDup ( aRRDFPath );
513     params [i++] = StrDup ( "-t" );
514     params [i++] = StrDup ( "read:writ:haRd:reRd:haWr:reWr" );
515     params [i++] = StrConcat ( 13, ts, ":", read, ":", writ, ":", haRd,
516             ":", reRd, ":", haWr, ":", reWr );
517     RRDUpdate ( i, params, aRRDFPath );
518     while ( i > 0 ) free ( params [--i] );
519     free ( reWr );
520     free ( haWr );
521     free ( reRd );
522     free ( haRd );
523     free ( writ );
524     free ( read );
525     free ( ts );
526 }
527 
PlotDataRdWr(tFN * aFN,int aTiming,int aNow)528 void PlotDataRdWr ( tFN* aFN, int aTiming, int aNow )
529 {
530     tPP* pp = PPInit ();
531     int i = 0;
532     char* title = NULL;
533     char* vLabel = "[sectors/s]  <-- wr | rd -->";
534     char* params[1024]; /* Now that should be enough! */
535 
536     FNSetPNGData ( aFN, "rdwr", aTiming );
537     PPAddPlot ( pp, "read",    "sectors/s", FALSE );
538     PPAddPlot ( pp, "written", "sectors/s", FALSE );
539     title = StrConcat ( 4, hostName, " drive ", addInf, " I/O operations" );
540     i = PlotStdParams ( params, aFN, title, vLabel,
541             aTiming, aNow - rrdHBeat, 1024, PLOT_SI_AUTO, 0, 0, TRUE );
542     params [i++] = CreateDEF ( "readMR", aFN, "read", MAX );
543     params [i++] = CreateDEF ( "readAR", aFN, "read", AVG );
544     params [i++] = CreateDEF ( "writMR", aFN, "writ", MAX );
545     params [i++] = CreateDEF ( "writAR", aFN, "writ", AVG );
546     params [i++] = StrDup ( "CDEF:readM=readMR" );
547     params [i++] = StrDup ( "CDEF:readA=readAR" );
548     params [i++] = StrDup ( "CDEF:writM=writMR,-1,*" );
549     params [i++] = StrDup ( "CDEF:writA=writAR,-1,*" );
550     params [i++] = CreatePlot ( PLOT_AREA,  "readM", C_THRU_MAX, pp, 0, MAX, FALSE );
551     params [i++] = CreatePlot ( PLOT_LINE2, "readA", C_THRU_AVG, pp, 0, AVG, TRUE );
552     params [i++] = CreatePlot ( PLOT_AREA,  "writM", C_THRU_MAX, pp, 1, MAX, FALSE );
553     params [i++] = CreatePlot ( PLOT_LINE2, "writA", C_THRU_AVG, pp, 1, AVG, TRUE );
554     i = PlotPrintParams ( i, params, pp, 0, "readAR", "readAR", "readMR", "readMR", "%4.1lf" );
555     i = PlotPrintParams ( i, params, pp, 1, "writAR", "writAR", "writMR", "writMR", "%4.1lf" );
556     RRDGraph ( i, params, aFN, pp );
557     while ( i > 0 ) free ( params [--i] );
558     free ( title );
559     PPDone ( pp );
560     FNUnsetPNGData ( aFN );
561 }
562 
PlotDataECnt(tFN * aFN,int aTiming,int aNow)563 void PlotDataECnt ( tFN* aFN, int aTiming, int aNow )
564 {
565     tPP* pp = PPInit ();
566     int i = 0;
567     char* title = NULL;
568     char* vLabel = "[errors/s]  <-- wr | rd -->";
569     char* params[1024]; /* Now that should be enough! */
570 
571     FNSetPNGData ( aFN, "ecnt", aTiming );
572     PPAddPlot ( pp, "recovered read errors",  "errors/s", FALSE );
573     PPAddPlot ( pp, "hard read errors",       "errors/s", FALSE );
574     PPAddPlot ( pp, "recovered write errors", "errors/s", FALSE );
575     PPAddPlot ( pp, "hard write errors",      "errors/s", FALSE );
576     title = StrConcat ( 4, hostName, " drive ", addInf, " errors" );
577     i = PlotStdParams ( params, aFN, title, vLabel,
578             aTiming, aNow - rrdHBeat, 1000, PLOT_SI_NONE, 0, 0, TRUE );
579     params [i++] = CreateDEF ( "reRdMR", aFN, "reRd", MAX );
580     params [i++] = CreateDEF ( "reRdAR", aFN, "reRd", AVG );
581     params [i++] = CreateDEF ( "haRdMR", aFN, "haRd", MAX );
582     params [i++] = CreateDEF ( "haRdAR", aFN, "haRd", AVG );
583     params [i++] = CreateDEF ( "reWrMR", aFN, "reWr", MAX );
584     params [i++] = CreateDEF ( "reWrAR", aFN, "reWr", AVG );
585     params [i++] = CreateDEF ( "haWrMR", aFN, "haWr", MAX );
586     params [i++] = CreateDEF ( "haWrAR", aFN, "haWr", AVG );
587     params [i++] = StrDup ( "CDEF:reRdM=reRdMR" );
588     params [i++] = StrDup ( "CDEF:reRdA=reRdAR" );
589     params [i++] = StrDup ( "CDEF:haRdM=haRdMR" );
590     params [i++] = StrDup ( "CDEF:haRdA=haRdAR" );
591     params [i++] = StrDup ( "CDEF:reWrM=reWrMR,-1,*" );
592     params [i++] = StrDup ( "CDEF:reWrA=reWrAR,-1,*" );
593     params [i++] = StrDup ( "CDEF:haWrM=haWrMR,-1,*" );
594     params [i++] = StrDup ( "CDEF:haWrA=haWrAR,-1,*" );
595     params [i++] = CreatePlot ( PLOT_AREA,  "reRdM", C_ERR2_MAX, pp, 0, MAX, FALSE );
596     params [i++] = CreatePlot ( PLOT_LINE2, "reRdA", C_ERR2_AVG, pp, 0, AVG, TRUE );
597     params [i++] = CreatePlot ( PLOT_LINE2, "haRdM", C_ERR1_MAX, pp, 1, MAX, FALSE );
598     params [i++] = CreatePlot ( PLOT_LINE2, "haRdA", C_ERR1_AVG, pp, 1, AVG, TRUE );
599     params [i++] = CreatePlot ( PLOT_AREA,  "reWrM", C_ERR2_MAX, pp, 2, MAX, FALSE );
600     params [i++] = CreatePlot ( PLOT_LINE2, "reWrA", C_ERR2_AVG, pp, 2, AVG, TRUE );
601     params [i++] = CreatePlot ( PLOT_LINE2, "haWrM", C_ERR1_MAX, pp, 3, MAX, FALSE );
602     params [i++] = CreatePlot ( PLOT_LINE2, "haWrA", C_ERR1_AVG, pp, 3, AVG, TRUE );
603     i = PlotPrintParams ( i, params, pp, 0, "reRdAR", "reRdAR", "reRdMR", "reRdMR", "%4.1lf" );
604     i = PlotPrintParams ( i, params, pp, 1, "haRdAR", "haRdAR", "haRdMR", "haRdMR", "%4.1lf" );
605     i = PlotPrintParams ( i, params, pp, 2, "reWrAR", "reWrAR", "reWrMR", "reWrMR", "%4.1lf" );
606     i = PlotPrintParams ( i, params, pp, 3, "haWrAR", "haWrAR", "haWrMR", "haWrMR", "%4.1lf" );
607     RRDGraph ( i, params, aFN, pp );
608     while ( i > 0 ) free ( params [--i] );
609     free ( title );
610     PPDone ( pp );
611     FNUnsetPNGData ( aFN );
612 }
613 
PlotPerfData()614 void PlotPerfData ()
615 {
616     int now = time ( NULL );
617     tFN* fn = FNInit ();
618 
619     PlotDataRdWr ( fn, PLOT_24H_5M,  now );
620     PlotDataECnt ( fn, PLOT_24H_5M,  now );
621     PlotDataRdWr ( fn, PLOT_7D_15M,  now );
622     PlotDataECnt ( fn, PLOT_7D_15M,  now );
623     PlotDataRdWr ( fn, PLOT_31D_60M, now );
624     PlotDataECnt ( fn, PLOT_31D_60M, now );
625     PlotDataRdWr ( fn, PLOT_366D_4H, now );
626     PlotDataECnt ( fn, PLOT_366D_4H, now );
627     FNDone ( fn );
628 }
629 #endif /* WITH_RRD */
630 
CheckStatus(int * aRetVal)631 char* CheckStatus ( int* aRetVal )
632 {
633     char* aRetStr = NULL;
634 
635     switch ( v.stat )
636     {
637         case 1:
638             aRetStr = StrDup ( "other" );
639             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
640         break;
641         case 2:
642             aRetStr = StrDup ( "ok" );
643         break;
644         case 3:
645             aRetStr = StrDup ( "critical" );
646             *aRetVal = MAXIMUM ( *aRetVal, STATE_CRITICAL );
647         break;
648         case 4:
649             aRetStr = StrDup ( "predictive failure" );
650             *aRetVal = MAXIMUM ( *aRetVal, STATE_CRITICAL );
651         break;
652         default:
653             aRetStr = StrDup ( "invalid" );
654             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
655         break;
656     }
657     return ( aRetStr );
658 }
659 
CheckCond(int * aRetVal)660 char* CheckCond ( int* aRetVal )
661 {
662     char* aRetStr = NULL;
663 
664     switch ( v.cond )
665     {
666         case 1:
667             aRetStr = StrDup ( "other" );
668             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
669         break;
670         case 2:
671             aRetStr = StrDup ( "ok" );
672         break;
673         case 3:
674             aRetStr = StrDup ( "degraded" );
675             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
676         break;
677         case 4:
678             aRetStr = StrDup ( "failed" );
679             *aRetVal = MAXIMUM ( *aRetVal, STATE_CRITICAL );
680         break;
681         default:
682             aRetStr = StrDup ( "invalid" );
683             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
684         break;
685     }
686     return ( aRetStr );
687 }
688 
CheckSmart(int * aRetVal)689 char* CheckSmart ( int* aRetVal )
690 {
691     char* aRetStr = NULL;
692 
693     switch ( v.smart )
694     {
695         case 1:
696             aRetStr = StrDup ( "other" );
697             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
698         break;
699         case 2:
700             aRetStr = StrDup ( "ok" );
701         break;
702         case 3:
703             aRetStr = StrDup ( "replace drive" );
704             *aRetVal = MAXIMUM ( *aRetVal, STATE_CRITICAL );
705         break;
706         default:
707             aRetStr = StrDup ( "invalid" );
708             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
709         break;
710     }
711     return ( aRetStr );
712 }
713 
CheckThreshold(int * aRetVal)714 char* CheckThreshold ( int* aRetVal )
715 {
716     char* aRetStr = NULL;
717 
718     switch ( v.thres )
719     {
720         case 1:
721             aRetStr = StrDup ( "ok" );
722         break;
723         case 2:
724             aRetStr = StrDup ( "exceeded" );
725             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
726         break;
727         default:
728             aRetStr = StrDup ( "invalid" );
729             *aRetVal = MAXIMUM ( *aRetVal, STATE_WARNING );
730         break;
731     }
732     return ( aRetStr );
733 }
734 
CheckData()735 int CheckData ()
736 {
737     int retVal = STATE_OK;
738     char* stat = NULL;
739     char* cond = NULL;
740     char* smart = NULL;
741     char* thres = NULL;
742 
743     ReadVals ();
744     stat  = CheckStatus    ( &retVal );
745     cond  = CheckCond      ( &retVal );
746     smart = CheckSmart     ( &retVal );
747     thres = CheckThreshold ( &retVal );
748     PrintExit ( retVal );
749     printf ( " - bay %i: %ud %uh, stat: %s, cond: %s, SMART: %s, thres: %s",
750             v.bay, v.hours / 24, v.hours % 24, stat, cond, smart, thres );
751     if ( npPerfData )
752     {
753         printf ( "|'sectors read'=%uc", v.read );
754         printf ( " 'sectors written'=%uc", v.writ );
755         printf ( " 'hard read errors'=%uc", v.haRd );
756         printf ( " 'recovered read errors'=%uc", v.reRd );
757         printf ( " 'hard write errors'=%uc", v.haWr );
758         printf ( " 'recovered write errors'=%uc\n", v.reWr );
759     }
760     else
761     {
762         printf ( "|%s;%u;%u;%u;%u;%u;%u\n",
763                 addInf, v.read, v.writ, v.haRd, v.reRd, v.haWr, v.reWr );
764     }
765     return ( retVal );
766 }
767 
main(int argc,char ** argv)768 int main ( int argc, char** argv )
769 {
770     int retVal = STATE_OK;
771 
772     SetGlobals ();
773     ReadArgs ( argc, argv );
774 
775     if ( checkData )
776     {
777         if ( !isPDrvSet ) Usage ( "Missing 'drive' parameters" );
778     }
779     if ( scanServices ) retVal = ScanServices ();
780     else
781     {
782         if ( checkData ) retVal = CheckData ();
783 #if(WITH_RRD)
784         if ( logPerfData ) LogPerfData ();
785         if ( plotPerfData ) PlotPerfData ();
786 #endif /* WITH_RRD */
787     }
788     if ( hostName != NULL ) free ( hostName );
789     if ( hostAddr != NULL ) free ( hostAddr );
790     if ( progName != NULL ) free ( progName );
791     return retVal;
792 }
793