1 /*
2  * File:      check_netapp_spare.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 #include "snmpif.h"
33 #include "syslogif.h"
34 #include "strutils.h"
35 #include "utilities.h"
36 
37 
38 /* data type for storing scan results */
39 typedef struct
40 {
41     int pDrv ;   /* spare drive index */
42     int v1;      /* found spareIndex */
43     int v3;      /* found spareStatus */
44     int v12;     /* found spareShelf */
45     int v13;     /* found spareBay */
46     int shelf;   /* shelf */
47     int bay;     /* bay */
48 } tScanRes;
49 
50 /* data type for storing data */
51 typedef struct
52 {
53     int  stat;  /* status of the drive */
54     int  shlf;  /* shelf the drive is in */
55     int  bay;   /* bay the drive is in */
56 } tDataSet;
57 
58 /* global input variables */
59 int pDrv;
60 int isPDrvSet  = FALSE;
61 
62 /*
63  * NETWORK-APPLIANCE-MIB::spareStatus.PDRV = 1.3.6.1.4.1.789.1.6.3.1.3.PDRV
64  * NETWORK-APPLIANCE-MIB::spareShelf.PDRV  = 1.3.6.1.4.1.789.1.6.3.1.12.PDRV
65  * NETWORK-APPLIANCE-MIB::spareBay.PDRV    = 1.3.6.1.4.1.789.1.6.3.1.13.PDRV
66  */
67 oid baseOID [] = { 1, 3, 6, 1, 4, 1, 789, 1, 6, 3, 1 };
68 size_t baseOIDLen = 11;
69 
70 /* scan results */
71 tScanRes* scanRes = NULL;
72 int scanResLen = 0;
73 
74 /* results of the SNMP queries */
75 tDataSet v;
76 
77 
SetGlobals()78 void SetGlobals ()
79 {
80     /* progName is set by ReadArgs() */
81     srvName = "check_netapp_spare";
82     progVersion = "0.3";
83     helpIndexP = "-d DRIVE";
84     helpThresP = NULL;
85     helpPurpose =
86             "Checks the state of a spare drive of a NetApp(R) Filer.";
87     /* community is set by ReadArgs() */
88     /* commFile is set by ReadArgs() */
89     /* rrdStep is unused */
90     /* rrdHBeat is unused */
91     supportsPerfLog = FALSE;
92     hasIndexParam = FALSE;
93 }
94 
HelpSpecificParams()95 void HelpSpecificParams ()
96 {
97     printf (
98     "-d, --drive INTEGER\n"
99     "    Index of the spare drive.\n"
100     "\n"
101     );
102 }
103 
HelpExplain()104 void HelpExplain ()
105 {
106     printf (
107     "The plugin checks the overall state of a spare drive of a NetApp(R)\n"
108     "Filer."
109     "\n"
110     );
111 }
112 
HelpPerformanceData()113 void HelpPerformanceData ()
114 {
115     printf (
116     "There is no performance data provided.\n"
117     "\n"
118     );
119 }
120 
ChkOptSpecificParams(int argc,char ** argv,int * i)121 int ChkOptSpecificParams ( int argc, char** argv, int* i )
122 {
123     int ret = TRUE;
124     if (        !strcmp ( argv [(*i)], "-d" )
125             ||  !strcmp ( argv [(*i)], "--drive" ) )
126     {
127         isPDrvSet = TRUE;
128         (*i)++;
129         if ( (*i) < argc )
130         {
131             char *tail = argv [(*i)];
132             errno = 0;
133             pDrv = strtoul ( argv [(*i)++], &tail, 0 );
134             if ( errno || *tail ) Usage ( "Invalid 'drive' parameter" );
135         }
136         else Usage ( "Missing 'drive' parameter(s)" );
137     } else ret = FALSE;
138     return ( ret );
139 }
140 
ScanResIndex(int aIndex)141 int ScanResIndex ( int aIndex )
142 {
143     int retVal = 0;
144     int found = FALSE;
145 
146     while ( ( retVal < scanResLen ) && !found )
147     {
148         found = ( scanRes [retVal].pDrv == aIndex );
149         if ( !found ) retVal++;
150     }
151     if ( !found ) retVal = -1;
152     return retVal;
153 }
154 
SnmpWalkHandleVariable(netsnmp_variable_list * aVar)155 void SnmpWalkHandleVariable ( netsnmp_variable_list* aVar )
156 {
157     if ( aVar->name_length == 13 )
158     {
159         if ( OidCmp ( aVar->name, baseOID, baseOIDLen ) == 0 )
160         {
161             int index;
162 
163             switch ( aVar->name [11] )
164             {
165                 case 1: /* spareIndex */
166                     index = scanResLen;
167                     scanResLen++;
168                     scanRes = realloc ( scanRes,
169                             sizeof ( tScanRes ) * scanResLen );
170                     if ( scanRes == NULL ) ErrorMalloc ();
171                     scanRes [index].pDrv = aVar->name [12];
172                     scanRes [index].v1 = ( aVar->type == ASN_INTEGER );
173                     scanRes [index].v3 = FALSE;
174                     scanRes [index].v12 = FALSE;
175                     scanRes [index].v13 = FALSE;
176                 break;
177                 case 3: /* spareStatus */
178                     index = ScanResIndex ( aVar->name [12] );
179                     scanRes [index].v3 = ( aVar->type == ASN_INTEGER );
180                 break;
181                 case 12: /* spareShelf */
182                     index = ScanResIndex ( aVar->name [12] );
183                     scanRes [index].v12 = ( aVar->type == ASN_INTEGER );
184                     scanRes [index].shelf = *(aVar->val.integer);
185                 break;
186                 case 13: /* spareBay */
187                     index = ScanResIndex ( aVar->name [12] );
188                     scanRes [index].v13 = ( aVar->type == ASN_INTEGER );
189                     scanRes [index].bay = *(aVar->val.integer);
190                 break;
191                 default:
192                     /* don't care */
193                 break;
194             }
195         } else Log ( LOG_CRIT, "Unexpected OID while scanning services" );
196     } else Log ( LOG_CRIT, "Wrong length while scanning services" );
197 }
198 
ScanServices()199 int ScanServices ()
200 {
201     int i;
202     int retVal = STATE_UNKNOWN;
203 
204     SnmpWalk ( baseOID, baseOIDLen );
205     for ( i = 0; i < scanResLen; i++ )
206     {
207         if (    scanRes [i].v1  && scanRes [i].v3  && scanRes [i].v12 &&
208                 scanRes [i].v13 )
209         {
210             retVal = STATE_OK;
211             printf ( "OK drive: %i ; shelf: %i ; bay: %i\n",
212                     scanRes [i].pDrv, scanRes [i].shelf, scanRes [i].bay );
213         }
214     }
215     if ( retVal == STATE_UNKNOWN ) printf ( "FAILED\n" );
216     return retVal;
217 }
218 
ReadVals()219 void ReadVals ()
220 {
221     struct snmp_session sess1;
222     struct snmp_session* sess2;
223     oid o_stat [13];
224     oid o_shlf [13];
225     oid o_bay  [13];
226     size_t oidLen;
227 
228     OidCpy ( o_stat, &oidLen, baseOID, &baseOIDLen );
229     OidCpy ( o_shlf, &oidLen, baseOID, &baseOIDLen );
230     OidCpy ( o_bay,  &oidLen, baseOID, &baseOIDLen );
231     o_stat [11] =  3; o_stat [12] = pDrv;
232     o_shlf [11] = 12; o_shlf [12] = pDrv;
233     o_bay  [11] = 13; o_bay  [12] = pDrv;
234     oidLen = 13;
235     ConfigureSession1 ( &sess1 );
236     sess2 = snmp_open ( &sess1 );
237     if ( sess2 == NULL ) Error ( LOG_ERR, "Could not open session!" );
238     v.stat = ReadInteger   ( sess2, o_stat, oidLen );
239     v.shlf = ReadInteger   ( sess2, o_shlf, oidLen );
240     v.bay  = ReadInteger   ( sess2, o_bay,  oidLen );
241     free ( sess1.peername );
242     free ( sess1.community );
243     snmp_close_sessions ();
244 }
245 
CreateDataFile(const char * aRRDFPath)246 void CreateDataFile ( const char* aRRDFPath )
247 {
248     /* performance data is not supported */
249 }
250 
ParseData(const char * aData)251 void ParseData ( const char* aData )
252 {
253     /* performance data is not supported */
254 }
255 
WriteData(const char * aRRDFPath)256 void WriteData ( const char* aRRDFPath )
257 {
258     /* performance data is not supported */
259 }
260 
CheckData()261 int CheckData ()
262 {
263     int retVal = STATE_OK;
264     char* mStat = NULL;
265 
266     ReadVals ();
267     switch ( v.stat )
268     {
269         case 1:
270             mStat = StrDup ( "spare" );
271         break;
272         case 2:
273             retVal = ( retVal < STATE_WARNING ) ? STATE_WARNING : retVal;
274             mStat = StrDup ( "adding spare" );
275         break;
276         case 3:
277             retVal = ( retVal < STATE_WARNING ) ? STATE_WARNING : retVal;
278             mStat = StrDup ( "bypassed" );
279         break;
280         case 4:
281             retVal = ( retVal < STATE_WARNING ) ? STATE_WARNING : retVal;
282             mStat = StrDup ( "unknown" );
283         break;
284         default:
285             retVal = ( retVal < STATE_WARNING ) ? STATE_WARNING : retVal;
286             mStat = StrDup ( "invalid" );
287         break;
288     }
289     PrintExit ( retVal );
290     printf ( " - shelf %i, bay %i: %s\n", v.shlf, v.bay, mStat );
291     free ( mStat );
292     return ( retVal );
293 }
294 
main(int argc,char ** argv)295 int main ( int argc, char** argv )
296 {
297     int retVal = STATE_OK;
298 
299     SetGlobals ();
300     ReadArgs ( argc, argv );
301     if ( checkData )
302     {
303         if ( !isPDrvSet ) Usage ( "Missing 'drive' parameters" );
304     }
305     if ( scanServices ) retVal = ScanServices ();
306     else
307     {
308         if ( checkData ) retVal = CheckData ();
309     }
310     if ( hostName != NULL ) free ( hostName );
311     if ( hostAddr != NULL ) free ( hostAddr );
312     if ( progName != NULL ) free ( progName );
313     return ( retVal );
314 }
315