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