1 /*
2  * File:      utilities.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 <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include "globals.h"
34 #include "nagiosif.h"
35 #include "snmpif.h"
36 #include "strutils.h"
37 
38 
HelpCopyright()39 void HelpCopyright ()
40 {
41     printf ( "%s %s (SNMP4Nagios %s)\n", progName, progVersion, VERSION );
42     printf (
43     "\n"
44     "Copyright (c) 2006 Peter Gritsch\n"
45     "SNMP4Nagios is free software; you can redistribute it and/or modify\n"
46     "it under the terms of the GNU General Public License. See the file\n"
47     "COPYING for more details.\n"
48     "\n"
49     );
50 }
51 
HelpUsage()52 void HelpUsage ()
53 {
54     if ( helpIndexP == NULL )
55             printf ( "Usage: %s\n", progName );
56     else    printf ( "Usage: %s %s\n", progName, helpIndexP );
57     if ( helpThresP == NULL ) printf ( "       [-S] [-T]" );
58     else                      printf ( "       [-S] [-T %s ]", helpThresP );
59 #if(WITH_RRD)
60     if ( supportsPerfLog ) printf ( " [-L] [-P]" );
61 #endif /* WITH_RRD */
62     printf ( " [-V] [-h]\n" );
63     printf ( "       [-H HOST] [-A ADDRESS] [-C COMMUNITY|-F COMMFILE]\n" );
64     printf ( "       [-v] [-1|-2] [-r RETRIES] [-t TIMEOUT ]\n" );
65 #if(WITH_RRD)
66     if ( supportsPerfLog ) printf ( "       [-R RRDDIR] [-G GRAPHDIR]\n" );
67 #endif /* WITH_RRD */
68 }
69 
HelpModesStd()70 void HelpModesStd ()
71 {
72     printf (
73     "Modes:\n"
74     "\n"
75     "-S, --scan\n"
76     "    Scan the host for services. This disables all other modes.\n"
77     "\n"
78     "-T, --test\n"
79     "    Check the service.\n"
80     "\n"
81     );
82 }
83 
84 #if(WITH_RRD)
HelpModesPerflog()85 void HelpModesPerflog ()
86 {
87     printf (
88     "-L, --log\n"
89     "    Log performance data. If -T is given, then the data is passed\n"
90     "    internally from the check otherwise it is read from the\n"
91     "    environment.\n"
92     "\n"
93     "-P, --plot\n"
94     "    Create plots.\n"
95     "\n"
96     );
97 }
98 #endif /* WITH_RRD */
99 
HelpModesOther()100 void HelpModesOther ()
101 {
102     printf (
103     "-V, --version\n"
104     "    Print version and exit.\n"
105     "\n"
106     "-h, --help\n"
107     "    This help.\n"
108     "\n"
109     );
110 }
111 
HelpGeneral()112 void HelpGeneral ()
113 {
114     printf (
115     "General options:\n"
116     "\n"
117     "-H, --host HOSTNAME\n"
118     "    Name of the host which should be be checked. This defaults to the\n"
119     "    contents of the environment variable $NAGIOS_HOSTNAME and is\n"
120     "    needed for logging and plotting.\n"
121     "\n"
122     "-A, --address BYTE.BYTE.BYTE.BYTE\n"
123     "    IP Address of the host which should be checkded. This defaults to\n"
124     "    the contents of the environment variable $NAGIOS_HOSTADDRESS and\n"
125     "    is preferred for setting up SNMP connections.\n"
126     "\n"
127     );
128     printf (
129     "-v, --verbose\n"
130     "    Increase verbosity. This can be given several times but there may\n"
131     "    simply be nothing more to say. Note also that messages are written\n"
132     "    to syslog and that you might need to use three '-v's to see\n"
133     "    anything.\n"
134     "\n"
135     );
136     printf (
137     "-N, --nagios-plugins-format\n"
138     "    Use the alternative 'Nagios Plugins' performance data format.\n"
139     "\n"
140     );
141 }
142 
HelpSNMP()143 void HelpSNMP ()
144 {
145     printf (
146     "SNMP Options:\n"
147     "\n"
148     "-1, --snmp-v1\n"
149     "    Use the SNMP protocol version 1.\n"
150     "\n"
151     "-2, --snmp-v2c\n"
152     "    Use the SNMP protocol version 2c (default).\n"
153     "\n"
154     "-C, --community STRING\n"
155     "    Use the community STRING.\n"
156     "\n"
157     "-F, --community-file FILENAME\n"
158     "    Read the SNMP community string from FILENAME.\n"
159     "\n"
160     "-r, --retries INTEGER\n"
161     "    Number of times to retry a request. Note that net-snmp uses\n"
162     "    increasing timeouts for retries.\n"
163     "\n"
164     "-t, --snmp-timeout INTEGER\n"
165     "    Timeout for the first SNMP request in milliseconds.\n"
166     "\n"
167     );
168     printf (
169     "If a community string is provided (-C) then it is used. Else if a\n"
170     "community file is provided, then the community is read from it.\n"
171     "Per default the program tries to read the community string from the\n"
172     "files $HOME/.snmp4nagios/community, <home>/.snmp4nagios/community\n"
173     "(where <home> is read from /etc/passwd) and /etc/snmp4nagios/community.\n"
174     "The first file that can be read is used. If no community is given, then\n"
175     "the program will use the community 'public'.\n"
176     "\n"
177     );
178 }
179 
180 #if(WITH_RRD)
HelpOptionsLogPlot()181 void HelpOptionsLogPlot ()
182 {
183     printf (
184     "Logging and plotting options:\n"
185     "\n"
186     "-R, --rrd-directory DIRNAME\n"
187     "    RRD archives' base directory. The filename of the archive is build\n"
188     "    by appending the hostname, the check's name and -- depending on the\n"
189     "    service -- other information to DIRNAME. If this option is not\n"
190     "    given, then the compiled in default is used.\n"
191     "\n"
192     );
193     printf (
194     "-G, --graph-directory DIRNAME\n"
195     "    PNG plots' base directory. The filename of the plots is build by\n"
196     "    appending the hostname, the check's name and -- depending on the\n"
197     "    service -- other information to DIRNAME. If this option is not\n"
198     "    given, then the compiled in default is used.\n"
199     "\n"
200     );
201     if ( hasAddInfParam )
202     {
203         printf (
204         "-I, --additional-info ADDINF\n"
205         "    Additional info used to find the RRD archive and image pathes.\n"
206         "\n"
207         );
208     }
209 }
210 #endif /* WITH_RRD */
211 
Version()212 void Version ()
213 {
214     HelpCopyright ();
215     exit ( STATE_OK );
216 }
217 
Usage(char * aMsg)218 void Usage ( char* aMsg )
219 {
220     printf ( "Usage error: %s\n", aMsg );
221     HelpUsage ();
222     exit ( STATE_UNKNOWN );
223 }
224 
Help()225 void Help ()
226 {
227     HelpCopyright ();
228     printf ( "%s\n", helpPurpose );
229     printf ( "\n" );
230     HelpUsage ();
231     printf ( "\n" );
232     HelpModesStd ();
233 #if(WITH_RRD)
234     if ( supportsPerfLog ) HelpModesPerflog ();
235 #endif /* WITH_RRD */
236     HelpModesOther ();
237     HelpGeneral ();
238     HelpSNMP ();
239 #if(WITH_RRD)
240     if ( supportsPerfLog ) HelpOptionsLogPlot ();
241 #endif /* WITH_RRD */
242     printf ( "Plugin-specific parameters:\n" );
243     printf ( "\n" );
244     HelpSpecificParams ();
245     HelpExplain ();
246     if ( supportsPerfLog ) HelpPerformanceData ();
247     exit ( STATE_OK );
248 }
249 
ChkOptModesStd(int argc,char ** argv,int * i)250 int ChkOptModesStd ( int argc, char** argv, int* i )
251 {
252     int ret = TRUE;
253 
254     if (        !strcmp ( argv [(*i)], "-S" )
255             ||  !strcmp ( argv [(*i)], "--scan" ) )
256     {
257         scanServices = TRUE;
258         (*i)++;
259     } else if ( !strcmp ( argv [(*i)], "-T" )
260             ||  !strcmp ( argv [(*i)], "--test" ) )
261     {
262         checkData = TRUE;
263         (*i)++;
264     } else ret = FALSE;
265     return ( ret );
266 }
267 
268 #if(WITH_RRD)
ChkOptModesPerflog(int argc,char ** argv,int * i)269 int ChkOptModesPerflog ( int argc, char** argv, int* i )
270 {
271     int ret = TRUE;
272 
273     if (        !strcmp ( argv [(*i)], "-L" )
274             ||  !strcmp ( argv [(*i)], "--log" ) )
275     {
276         logPerfData = TRUE;
277         (*i)++;
278     } else if ( !strcmp ( argv [(*i)], "-P" )
279             ||  !strcmp ( argv [(*i)], "--plot" ) )
280     {
281         plotPerfData = TRUE;
282         (*i)++;
283     } else ret = FALSE;
284     return ( ret );
285 }
286 #endif /* WITH_RRD */
287 
ChkOptModesOther(int argc,char ** argv,int * i)288 int ChkOptModesOther ( int argc, char** argv, int* i )
289 {
290     int ret = TRUE;
291 
292     if (        !strcmp ( argv [(*i)], "-V" )
293             ||  !strcmp ( argv [(*i)], "--version" ) )
294     {
295         Version ();
296     } else if ( !strcmp ( argv [(*i)], "-h" )
297             ||  !strcmp ( argv [(*i)], "--help" ) )
298     {
299         Help ();
300     } else ret = FALSE;
301     return ( ret );
302 }
303 
ChkOptGeneral(int argc,char ** argv,int * i)304 int ChkOptGeneral ( int argc, char** argv, int* i )
305 {
306     int ret = TRUE;
307 
308     if (        !strcmp ( argv [(*i)], "-H" )
309             ||  !strcmp ( argv [(*i)], "--host" ) )
310     {
311         isHostNameSet = TRUE;
312         (*i)++;
313         if ( (*i) < argc ) hostName = StrDup ( argv [(*i)++] );
314         else Usage ( "Missing 'host' parameter" );
315     } else if ( !strcmp ( argv [(*i)], "-A" )
316             ||  !strcmp ( argv [(*i)], "--address" ) )
317     {
318         isHostAddrSet = TRUE;
319         (*i)++;
320         if ( (*i) < argc ) hostAddr = StrDup ( argv [(*i)++] );
321         else Usage ( "Missing 'address' parameter" );
322     } else if ( !strcmp ( argv [(*i)], "-v" )
323             ||  !strcmp ( argv [(*i)], "--verbose" ) )
324     {
325         switch ( loggingLevel )
326         {
327             case LOG_EMERG:
328             case LOG_ALERT:
329             case LOG_CRIT:
330             case LOG_ERR:
331                 loggingLevel = LOG_WARNING;
332             break;
333             case LOG_WARNING:
334                 loggingLevel = LOG_NOTICE;
335             break;
336             case LOG_NOTICE:
337                 loggingLevel = LOG_DEBUG;
338             break;
339             case LOG_INFO:
340             case LOG_DEBUG:
341             break;
342             default:
343                 loggingLevel = LOG_ERR;
344             break;
345         }
346         (*i)++;
347     } else if ( !strcmp ( argv [(*i)], "-N" )
348             ||  !strcmp ( argv [(*i)], "--nagios-plugins-format" ) )
349     {
350         npPerfData = TRUE;
351         (*i)++;
352     } else ret = FALSE;
353     return ( ret );
354 }
355 
ChkOptSNMP(int argc,char ** argv,int * i)356 int ChkOptSNMP ( int argc, char** argv, int* i )
357 {
358     int ret = TRUE;
359 
360     if (        !strcmp ( argv [(*i)], "-1" )
361             ||  !strcmp ( argv [(*i)], "--snmp-v1" ) )
362     {
363         snmpVersion = SNMP_VERSION_1;
364         (*i)++;
365     } else if ( !strcmp ( argv [(*i)], "-2" )
366             ||  !strcmp ( argv [(*i)], "--snmp-v2c" ) )
367     {
368         snmpVersion = SNMP_VERSION_2c;
369         (*i)++;
370     } else if ( !strcmp ( argv [(*i)], "-C" )
371             ||  !strcmp ( argv [(*i)], "--community" ) )
372     {
373         (*i)++;
374         if ( (*i) < argc ) community = argv [(*i)++];
375         else Usage ( "Missing 'community' parameter" );
376     } else if ( !strcmp ( argv [(*i)], "-F" )
377             ||  !strcmp ( argv [(*i)], "--community-file" ) )
378     {
379         (*i)++;
380         if ( (*i) < argc ) commFile = argv [(*i)++];
381         else Usage ( "Missing 'community file' parameter" );
382     } else if ( !strcmp ( argv [(*i)], "-r" )
383             ||  !strcmp ( argv [(*i)], "--retries" ) )
384     {
385         (*i)++;
386         if ( (*i) < argc )
387         {
388             char *tail = argv [(*i)];
389             errno = 0;
390             snmpRetries = strtoul ( argv [(*i)++], &tail, 0 );
391             if ( errno || *tail )
392                     Usage ( "Invalid 'retries' parameter" );
393         }
394         else Usage ( "Missing 'retries' parameter" );
395     } else if ( !strcmp ( argv [(*i)], "-t" )
396             ||  !strcmp ( argv [(*i)], "--snmp-timeout" ) )
397     {
398         (*i)++;
399         if ( (*i) < argc )
400         {
401             char *tail = argv [(*i)];
402             errno = 0;
403             snmpTimeOut = 1000 * strtoul ( argv [(*i)++], &tail, 0 );
404             if ( errno || *tail )
405                     Usage ( "Invalid 'SNMP timeout' parameter" );
406         }
407         else Usage ( "Missing 'SNMP timeout' parameter" );
408     } else ret = FALSE;
409     return ( ret );
410 }
411 
412 #if(WITH_RRD)
ChkOptLogPlot(int argc,char ** argv,int * i)413 int ChkOptLogPlot ( int argc, char** argv, int* i )
414 {
415     int ret = TRUE;
416 
417     if (        !strcmp ( argv [(*i)], "-R" )
418             ||  !strcmp ( argv [(*i)], "--rrd-directory" ) )
419     {
420         (*i)++;
421         if ( (*i) < argc )
422         {
423             rrdDir = argv [(*i)++];
424         } else
425         {
426             Usage ( "Missing 'rrd-directory' parameter" );
427         }
428     } else if ( !strcmp ( argv [(*i)], "-G" )
429             ||  !strcmp ( argv [(*i)], "--graph-directory" ) )
430     {
431         (*i)++;
432         if ( (*i) < argc )
433         {
434             pngDir = argv [(*i)++];
435         } else
436         {
437             Usage ( "Missing 'graph-directory' parameter" );
438         }
439     } else ret = FALSE;
440     return ( ret );
441 }
442 #endif /* WITH_RRD */
443 
ChkOptAddInf(int argc,char ** argv,int * i)444 int ChkOptAddInf ( int argc, char** argv, int* i )
445 {
446     int ret = TRUE;
447 
448     if (        !strcmp ( argv [(*i)], "-I" )
449             ||  !strcmp ( argv [(*i)], "--additional-info" ) )
450     {
451         (*i)++;
452         if ( (*i) < argc )
453         {
454             addInf = argv [(*i)++];
455             isAddInfSet = TRUE;
456         } else
457         {
458             Usage ( "Missing 'graph-directory' parameter" );
459         }
460     } else ret = FALSE;
461     return ( ret );
462 }
463 
ChkOptIndex(int argc,char ** argv,int * i)464 int ChkOptIndex ( int argc, char** argv, int* i )
465 {
466     int ret = TRUE;
467 
468     if (        !strcmp ( argv [(*i)], "-i" )
469             ||  !strcmp ( argv [(*i)], "--index" ) )
470     {
471         isIdxSet = TRUE;
472         (*i)++;
473         if ( (*i) < argc )
474         {
475             char *tail = argv [(*i)];
476 
477             errno = 0;
478             idx = strtoul ( argv [(*i)++], &tail, 0 );
479             if ( errno || *tail ) Usage ( "Invalid 'index' parameter" );
480         }
481         else Usage ( "Missing 'index' parameter" );
482     } else ret = FALSE;
483     return ( ret );
484 }
485 
ReadArgs(int argc,char ** argv)486 void ReadArgs ( int argc, char** argv )
487 {
488     int i = 0;
489 
490     ReadHostName ();
491     ReadHostAddr ();
492     progName = Basename ( argv [i++] );
493     while ( i < argc )
494     {
495         /*
496          * Note the semicolons at the end of the lines. IOW: Do nothing if the
497          * function returns TRUE.
498          */
499         if ( ChkOptModesStd ( argc, argv, &i ) );
500 #if(WITH_RRD)
501         else if ( supportsPerfLog && ChkOptModesPerflog ( argc, argv, &i ) );
502 #endif /* WITH_RRD */
503         else if ( ChkOptModesOther ( argc, argv, &i ) );
504         else if ( ChkOptGeneral ( argc, argv, &i ) );
505         else if ( ChkOptSNMP ( argc, argv, &i ) );
506 #if(WITH_RRD)
507         else if ( supportsPerfLog && ChkOptLogPlot ( argc, argv, &i ) );
508 #endif /* WITH_RRD */
509         else if ( hasAddInfParam && ChkOptAddInf ( argc, argv, &i ) );
510         else if ( hasIndexParam && ChkOptIndex ( argc, argv, &i ) );
511         else if ( ChkOptSpecificParams ( argc, argv, &i ) );
512         else
513         {
514             char msg[512] = "Unknown parameter: ";
515             strncat ( msg, argv [i], 256 );
516             Usage ( msg );
517         }
518     }
519     if ( checkData && hasIndexParam )
520     {
521         if ( !isIdxSet ) Usage ( "Missing 'index' parameters" );
522     }
523     if ( ( checkData
524 #if(WITH_RRD)
525             || logPerfData || plotPerfData
526 #endif /* WITH_RRD */
527             ) && hasAddInfParam )
528     {
529         if ( !isAddInfSet ) Usage ( "Missing 'addInf' parameters" );
530     }
531 #if(WITH_RRD)
532     if ( logPerfData || plotPerfData )
533     {
534         if ( !isHostNameSet ) Usage ( "'Missing 'host name' parameters" );
535     }
536 #endif /* WITH_RRD */
537     if ( !( isHostNameSet || isHostAddrSet ) )
538     {
539         Usage ( "Missing both 'host name' and 'host address' parameters" );
540     }
541 }
542