1 /*****************************************************************************
3 * Nagios check_snmp plugin
6 * Copyright (c) 1999-2007 Nagios Plugins Development Team
10 * This file contains the check_snmp plugin
12 * Check status of remote machines and obtain system information via SNMP
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *****************************************************************************/
31 const char *progname
= "check_snmp";
32 const char *copyright
= "1999-2007";
33 const char *email
= "nagiosplug-devel@lists.sourceforge.net";
37 #include "utils_cmd.h"
39 #define DEFAULT_COMMUNITY "public"
40 #define DEFAULT_PORT "161"
41 #define DEFAULT_MIBLIST "ALL"
42 #define DEFAULT_PROTOCOL "1"
43 #define DEFAULT_TIMEOUT 1
44 #define DEFAULT_RETRIES 5
45 #define DEFAULT_AUTH_PROTOCOL "MD5"
46 #define DEFAULT_PRIV_PROTOCOL "DES"
47 #define DEFAULT_DELIMITER "="
48 #define DEFAULT_OUTPUT_DELIMITER " "
50 #define mark(a) ((a)!=0?"*":"")
53 #define CRIT_PRESENT 1
56 #define WARN_PRESENT 8
57 #define WARN_STRING 16
62 /* Longopts only arguments */
63 #define L_CALCULATE_RATE CHAR_MAX+1
64 #define L_RATE_MULTIPLIER CHAR_MAX+2
65 #define L_INVERT_SEARCH CHAR_MAX+3
67 /* Gobble to string - stop incrementing c when c[0] match one of the
69 #define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
70 /* Given c, keep track of backslashes (bk) and double-quotes (dq)
72 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
79 else if(!bk) { dq--; } \
86 int process_arguments (int, char **);
87 int validate_arguments (void);
88 char *thisarg (char *str
);
89 char *nextarg (char *str
);
90 void print_usage (void);
91 void print_help (void);
94 char regex_expect
[MAX_INPUT_BUFFER
] = "";
96 regmatch_t pmatch
[10];
97 char errbuf
[MAX_INPUT_BUFFER
] = "";
98 char perfstr
[MAX_INPUT_BUFFER
] = "| ";
99 int cflags
= REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
;
103 char *server_address
= NULL
;
104 char *community
= NULL
;
105 char **authpriv
= NULL
;
107 char *seclevel
= NULL
;
108 char *secname
= NULL
;
109 char *authproto
= NULL
;
110 char *privproto
= NULL
;
111 char *authpasswd
= NULL
;
112 char *privpasswd
= NULL
;
118 char string_value
[MAX_INPUT_BUFFER
] = "";
120 char **labels
= NULL
;
123 size_t labels_size
= 8;
125 size_t unitv_size
= 8;
129 int usesnmpgetnext
= FALSE
;
130 char *warning_thresholds
= NULL
;
131 char *critical_thresholds
= NULL
;
132 thresholds
*thlds
[MAX_OIDS
];
133 double response_value
[MAX_OIDS
];
135 int eval_method
[MAX_OIDS
];
138 char *miblist
= NULL
;
139 int needmibs
= FALSE
;
140 int calculate_rate
= 0;
141 int rate_multiplier
= 1;
142 state_data
*previous_state
;
143 double previous_value
[MAX_OIDS
];
147 static char *fix_snmp_range(char *th
)
151 if (!(colon
= strchr(th
, ':')))
155 left
= strtod(th
, NULL
);
156 right
= strtod(colon
+ 1, NULL
);
160 ret
= malloc(strlen(th
) + strlen(colon
+ 1) + 2);
161 sprintf(ret
, "@%s:%s", colon
+ 1, th
);
167 main (int argc
, char **argv
)
169 int i
, len
, line
, total_oids
;
170 unsigned int bk_count
= 0, dq_count
= 0;
171 int iresult
= STATE_UNKNOWN
;
172 int result
= STATE_UNKNOWN
;
174 int external_error
= 0;
175 char **command_line
= NULL
;
176 char *cl_hidden_auth
= NULL
;
177 char *oidname
= NULL
;
178 char *response
= NULL
;
179 char *mult_resp
= NULL
;
186 output chld_out
, chld_err
;
187 char *previous_string
=NULL
;
189 char *state_string
=NULL
;
190 size_t response_length
, current_length
, string_length
;
191 char *temp_string
=NULL
;
192 char *quote_string
=NULL
;
196 char *conv
= "12345678";
199 setlocale (LC_ALL
, "");
200 bindtextdomain (PACKAGE
, LOCALEDIR
);
201 textdomain (PACKAGE
);
203 labels
= malloc (labels_size
* sizeof(*labels
));
204 unitv
= malloc (unitv_size
* sizeof(*unitv
));
205 for (i
= 0; i
< MAX_OIDS
; i
++)
206 eval_method
[i
] = CHECK_UNDEF
;
208 label
= strdup ("SNMP");
210 port
= strdup (DEFAULT_PORT
);
211 outbuff
= strdup ("");
212 delimiter
= strdup (" = ");
213 output_delim
= strdup (DEFAULT_OUTPUT_DELIMITER
);
214 timeout_interval
= DEFAULT_TIMEOUT
;
215 retries
= DEFAULT_RETRIES
;
217 np_init( (char *) progname
, argc
, argv
);
219 /* Parse extra opts if any */
220 argv
=np_extra_opts (&argc
, argv
, progname
);
222 np_set_args(argc
, argv
);
224 if (process_arguments (argc
, argv
) == ERROR
)
225 usage4 (_("Could not parse arguments"));
228 if (!strcmp(label
, "SNMP"))
229 label
= strdup("SNMP RATE");
232 previous_state
= np_state_read();
233 if(previous_state
!=NULL
) {
234 /* Split colon separated values */
235 previous_string
= strdup((char *) previous_state
->data
);
236 while((ap
= strsep(&previous_string
, ":")) != NULL
) {
238 printf("State for %d=%s\n", i
, ap
);
239 previous_value
[i
++]=strtod(ap
,NULL
);
244 /* Populate the thresholds */
245 th_warn
=warning_thresholds
;
246 th_crit
=critical_thresholds
;
247 for (i
=0; i
<numoids
; i
++) {
248 char *w
= th_warn
? strndup(th_warn
, strcspn(th_warn
, ",")) : NULL
;
249 char *c
= th_crit
? strndup(th_crit
, strcspn(th_crit
, ",")) : NULL
;
250 /* translate "2:1" to "@1:2" for backwards compatibility */
251 w
= w
? fix_snmp_range(w
) : NULL
;
252 c
= c
? fix_snmp_range(c
) : NULL
;
254 /* Skip empty thresholds, while avoiding segfault */
255 set_thresholds(&thlds
[i
],
256 w
? strpbrk(w
, NP_THRESHOLDS_CHARS
) : NULL
,
257 c
? strpbrk(c
, NP_THRESHOLDS_CHARS
) : NULL
);
259 th_warn
=strchr(th_warn
, ',');
260 if (th_warn
) th_warn
++;
264 th_crit
=strchr(th_crit
, ',');
265 if (th_crit
) th_crit
++;
270 /* Create the command array to execute */
271 if(usesnmpgetnext
== TRUE
) {
272 snmpcmd
= strdup (PATH_TO_SNMPGETNEXT
);
274 snmpcmd
= strdup (PATH_TO_SNMPGET
);
277 /* 9 arguments to pass before authpriv options + 1 for host and numoids. Add one for terminating NULL */
278 command_line
= calloc (9 + numauthpriv
+ 1 + numoids
+ 1, sizeof (char *));
279 command_line
[0] = snmpcmd
;
280 command_line
[1] = strdup ("-Le");
281 command_line
[2] = strdup ("-t");
282 xasprintf (&command_line
[3], "%d", timeout_interval
);
283 command_line
[4] = strdup ("-r");
284 xasprintf (&command_line
[5], "%d", retries
);
285 command_line
[6] = strdup ("-m");
286 command_line
[7] = strdup (miblist
);
287 command_line
[8] = "-v";
288 command_line
[9] = strdup (proto
);
290 for (i
= 0; i
< numauthpriv
; i
++) {
291 command_line
[10 + i
] = authpriv
[i
];
294 xasprintf (&command_line
[10 + numauthpriv
], "%s:%s", server_address
, port
);
296 /* This is just for display purposes, so it can remain a string */
297 xasprintf(&cl_hidden_auth
, "%s -Le -t %d -r %d -m %s -v %s %s %s:%s",
298 snmpcmd
, timeout_interval
, retries
, strlen(miblist
) ? miblist
: "''", proto
, "[authpriv]",
299 server_address
, port
);
301 for (i
= 0; i
< numoids
; i
++) {
302 command_line
[10 + numauthpriv
+ 1 + i
] = oids
[i
];
303 xasprintf(&cl_hidden_auth
, "%s %s", cl_hidden_auth
, oids
[i
]);
306 command_line
[10 + numauthpriv
+ 1 + numoids
] = NULL
;
309 printf ("%s\n", cl_hidden_auth
);
311 /* Run the command */
312 return_code
= cmd_run_array (command_line
, &chld_out
, &chld_err
, 0);
314 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
315 only return state unknown if return code is non zero or there is no stdout.
316 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
318 if (return_code
!= 0)
320 if (chld_out
.lines
== 0)
322 if (external_error
) {
323 if (chld_err
.lines
> 0) {
324 printf (_("External command error: %s\n"), chld_err
.line
[0]);
325 for (i
= 1; i
< chld_err
.lines
; i
++) {
326 printf ("%s\n", chld_err
.line
[i
]);
329 printf(_("External command error with no output (return code: %d)\n"), return_code
);
331 exit (STATE_UNKNOWN
);
335 for (i
= 0; i
< chld_out
.lines
; i
++) {
336 printf ("%s\n", chld_out
.line
[i
]);
340 for (line
=0, i
=0; line
< chld_out
.lines
; line
++, i
++) {
346 ptr
= chld_out
.line
[line
];
347 oidname
= strpcpy (oidname
, ptr
, delimiter
);
348 response
= strstr (ptr
, delimiter
);
349 if (response
== NULL
)
353 printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i
+1, line
+1, oidname
, response
);
356 /* Clean up type array - Sol10 does not necessarily zero it out */
357 bzero(type
, sizeof(type
));
360 /* We strip out the datatype indicator for PHBs */
361 if (strstr (response
, "Gauge: ")) {
362 show
= strstr (response
, "Gauge: ") + 7;
364 else if (strstr (response
, "Gauge32: ")) {
365 show
= strstr (response
, "Gauge32: ") + 9;
367 else if (strstr (response
, "Counter32: ")) {
368 show
= strstr (response
, "Counter32: ") + 11;
373 else if (strstr (response
, "Counter64: ")) {
374 show
= strstr (response
, "Counter64: ") + 11;
379 else if (strstr (response
, "INTEGER: ")) {
380 show
= strstr (response
, "INTEGER: ") + 9;
382 else if (strstr (response
, "STRING: ")) {
383 show
= strstr (response
, "STRING: ") + 8;
386 /* Get the rest of the string on multi-line strings */
388 COUNT_SEQ(ptr
, bk_count
, dq_count
)
389 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
391 GOBBLE_TOS(ptr
, "\n\"\\")
392 COUNT_SEQ(ptr
, bk_count
, dq_count
)
395 if (dq_count
) { /* unfinished line */
396 /* copy show verbatim first */
397 if (!mult_resp
) mult_resp
= strdup("");
398 xasprintf (&mult_resp
, "%s%s:\n%s\n", mult_resp
, oids
[i
], show
);
399 /* then strip out unmatched double-quote from single-line output */
400 if (show
[0] == '"') show
++;
402 /* Keep reading until we match end of double-quoted string */
403 for (line
++; line
< chld_out
.lines
; line
++) {
404 ptr
= chld_out
.line
[line
];
405 xasprintf (&mult_resp
, "%s%s\n", mult_resp
, ptr
);
407 COUNT_SEQ(ptr
, bk_count
, dq_count
)
408 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
410 GOBBLE_TOS(ptr
, "\n\"\\")
411 COUNT_SEQ(ptr
, bk_count
, dq_count
)
413 /* Break for loop before next line increment when done */
414 if (!dq_count
) break;
419 else if (strstr (response
, "Timeticks: ")) {
420 show
= strstr (response
, "Timeticks: ");
425 iresult
= STATE_DEPENDENT
;
427 /* Process this block for numeric comparisons */
428 /* Make some special values,like Timeticks numeric only if a threshold is defined */
429 if (thlds
[i
]->warning
|| thlds
[i
]->critical
|| calculate_rate
) {
430 ptr
= strpbrk (show
, "0123456789");
432 die (STATE_UNKNOWN
,_("No valid data returned (%s)\n"), show
);
433 response_value
[i
] = strtod (ptr
, NULL
);
436 if (previous_state
!=NULL
) {
437 duration
= current_time
-previous_state
->time
;
439 die(STATE_UNKNOWN
,_("Time duration between plugin calls is invalid"));
440 temp_double
= response_value
[i
]-previous_value
[i
];
441 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
443 if(temp_double
<(double)0.0)
444 temp_double
+=(double)4294967296.0; /* 2^32 */
445 if(temp_double
<(double)0.0)
446 temp_double
+=(double)18446744069414584320.0; /* 2^64-2^32 */;
448 /* Convert to per second, then use multiplier */
449 temp_double
= temp_double
/duration
*rate_multiplier
;
450 iresult
= get_status(temp_double
, thlds
[i
]);
451 xasprintf (&show
, conv
, temp_double
);
454 iresult
= get_status(response_value
[i
], thlds
[i
]);
455 xasprintf (&show
, conv
, response_value
[i
]);
459 /* Process this block for string matching */
460 else if (eval_method
[i
] & CRIT_STRING
) {
461 if (strcmp (show
, string_value
))
462 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
464 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
467 /* Process this block for regex matching */
468 else if (eval_method
[i
] & CRIT_REGEX
) {
469 excode
= regexec (&preg
, response
, 10, pmatch
, eflags
);
471 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
473 else if (excode
!= REG_NOMATCH
) {
474 regerror (excode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
475 printf (_("Execute Error: %s\n"), errbuf
);
476 exit (STATE_CRITICAL
);
479 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
483 /* Process this block for existence-nonexistence checks */
484 /* TV: Should this be outside of this else block? */
486 if (eval_method
[i
] & CRIT_PRESENT
)
487 iresult
= STATE_CRITICAL
;
488 else if (eval_method
[i
] & WARN_PRESENT
)
489 iresult
= STATE_WARNING
;
490 else if (response
&& iresult
== STATE_DEPENDENT
)
494 /* Result is the worst outcome of all the OIDs tested */
495 result
= max_state (result
, iresult
);
497 /* Prepend a label for this OID if there is one */
498 if (nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
499 xasprintf (&outbuff
, "%s%s%s %s%s%s", outbuff
,
500 (i
== 0) ? " " : output_delim
,
501 labels
[i
], mark (iresult
), show
, mark (iresult
));
503 xasprintf (&outbuff
, "%s%s%s%s%s", outbuff
, (i
== 0) ? " " : output_delim
,
504 mark (iresult
), show
, mark (iresult
));
506 /* Append a unit string for this OID if there is one */
507 if (nunits
> (size_t)0 && (size_t)i
< nunits
&& unitv
[i
] != NULL
)
508 xasprintf (&outbuff
, "%s %s", outbuff
, unitv
[i
]);
510 /* Write perfdata with whatever can be parsed by strtod, if possible */
514 if (perf_labels
&& nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
515 temp_string
=labels
[i
];
518 if (strpbrk (temp_string
, " ='\"") == NULL
) {
519 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
521 if (strpbrk (temp_string
, "'") == NULL
) {
526 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
527 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
528 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
530 strncat(perfstr
, "=", sizeof(perfstr
)-strlen(perfstr
)-1);
531 len
= sizeof(perfstr
)-strlen(perfstr
)-1;
532 strncat(perfstr
, show
, len
>ptr
-show
? ptr
-show
: len
);
535 strncat(perfstr
, type
, sizeof(perfstr
)-strlen(perfstr
)-1);
536 strncat(perfstr
, " ", sizeof(perfstr
)-strlen(perfstr
)-1);
541 /* Save state data, as all data collected now */
544 state_string
=malloc(string_length
);
545 if(state_string
==NULL
)
546 die(STATE_UNKNOWN
, _("Cannot malloc"));
549 for(i
=0; i
<total_oids
; i
++) {
550 xasprintf(&temp_string
,"%.0f",response_value
[i
]);
551 if(temp_string
==NULL
)
552 die(STATE_UNKNOWN
,_("Cannot asprintf()"));
553 response_length
= strlen(temp_string
);
554 if(current_length
+response_length
>string_length
) {
555 string_length
=current_length
+1024;
556 state_string
=realloc(state_string
,string_length
);
557 if(state_string
==NULL
)
558 die(STATE_UNKNOWN
, _("Cannot realloc()"));
560 strcpy(&state_string
[current_length
],temp_string
);
561 current_length
=current_length
+response_length
;
562 state_string
[current_length
]=':';
566 state_string
[--current_length
]='\0';
568 printf("State string=%s\n",state_string
);
570 /* This is not strictly the same as time now, but any subtle variations will cancel out */
571 np_state_write_string(current_time
, state_string
);
572 if(previous_state
==NULL
) {
573 /* Or should this be highest state? */
574 die( STATE_OK
, _("No previous data to calculate rate - assume okay" ) );
578 printf ("%s %s -%s %s\n", label
, state_text (result
), outbuff
, perfstr
);
579 if (mult_resp
) printf ("%s", mult_resp
);
586 /* process command-line arguments */
588 process_arguments (int argc
, char **argv
)
592 int j
= 0, jj
= 0, ii
= 0;
595 static struct option longopts
[] = {
597 {"community", required_argument
, 0, 'C'},
598 {"oid", required_argument
, 0, 'o'},
599 {"object", required_argument
, 0, 'o'},
600 {"delimiter", required_argument
, 0, 'd'},
601 {"output-delimiter", required_argument
, 0, 'D'},
602 {"string", required_argument
, 0, 's'},
603 {"timeout", required_argument
, 0, 't'},
604 {"regex", required_argument
, 0, 'r'},
605 {"ereg", required_argument
, 0, 'r'},
606 {"eregi", required_argument
, 0, 'R'},
607 {"label", required_argument
, 0, 'l'},
608 {"units", required_argument
, 0, 'u'},
609 {"port", required_argument
, 0, 'p'},
610 {"retries", required_argument
, 0, 'e'},
611 {"miblist", required_argument
, 0, 'm'},
612 {"protocol", required_argument
, 0, 'P'},
613 {"seclevel", required_argument
, 0, 'L'},
614 {"secname", required_argument
, 0, 'U'},
615 {"authproto", required_argument
, 0, 'a'},
616 {"privproto", required_argument
, 0, 'x'},
617 {"authpasswd", required_argument
, 0, 'A'},
618 {"privpasswd", required_argument
, 0, 'X'},
619 {"next", no_argument
, 0, 'n'},
620 {"rate", no_argument
, 0, L_CALCULATE_RATE
},
621 {"rate-multiplier", required_argument
, 0, L_RATE_MULTIPLIER
},
622 {"invert-search", no_argument
, 0, L_INVERT_SEARCH
},
623 {"perf-oids", no_argument
, 0, 'O'},
630 /* reverse compatibility for very old non-POSIX usage forms */
631 for (c
= 1; c
< argc
; c
++) {
632 if (strcmp ("-to", argv
[c
]) == 0)
633 strcpy (argv
[c
], "-t");
634 if (strcmp ("-wv", argv
[c
]) == 0)
635 strcpy (argv
[c
], "-w");
636 if (strcmp ("-cv", argv
[c
]) == 0)
637 strcpy (argv
[c
], "-c");
641 c
= getopt_long (argc
, argv
, "nhvVOt:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:L:U:a:x:A:X:",
644 if (c
== -1 || c
== EOF
)
648 case '?': /* usage */
653 case 'V': /* version */
654 print_revision (progname
, NP_VERSION
);
656 case 'v': /* verbose */
660 /* Connection info */
661 case 'C': /* group or community */
664 case 'H': /* Host or server */
665 server_address
= optarg
;
667 case 'p': /* TCP port number */
670 case 'm': /* List of MIBS */
673 case 'n': /* usesnmpgetnext */
674 usesnmpgetnext
= TRUE
;
676 case 'P': /* SNMP protocol version */
679 case 'L': /* security level */
682 case 'U': /* security username */
685 case 'a': /* auth protocol */
688 case 'x': /* priv protocol */
691 case 'A': /* auth passwd */
694 case 'X': /* priv passwd */
697 case 't': /* timeout period */
698 if (!is_integer (optarg
))
699 usage2 (_("Timeout interval must be a positive integer"), optarg
);
701 timeout_interval
= atoi (optarg
);
704 /* Test parameters */
705 case 'c': /* critical threshold */
706 critical_thresholds
= optarg
;
708 case 'w': /* warning threshold */
709 warning_thresholds
= optarg
;
711 case 'e': /* PRELIMINARY - may change */
712 case 'E': /* PRELIMINARY - may change */
713 if (!is_integer (optarg
))
714 usage2 (_("Retries interval must be a positive integer"), optarg
);
716 retries
= atoi(optarg
);
718 case 'o': /* object identifier */
719 if ( strspn( optarg
, "0123456789.," ) != strlen( optarg
) ) {
721 * we have something other than digits, periods and comas,
722 * so we have a mib variable, rather than just an SNMP OID,
723 * so we have to actually read the mib files
727 if (!oids
) oids
= calloc(MAX_OIDS
, sizeof (char *));
728 for (ptr
= strtok(optarg
, ", "); ptr
!= NULL
&& j
< MAX_OIDS
; ptr
= strtok(NULL
, ", "), j
++) {
729 oids
[j
] = strdup(ptr
);
732 if (c
== 'E' || c
== 'e') {
737 eval_method
[j
+1] |= WARN_PRESENT
;
739 eval_method
[j
+1] |= CRIT_PRESENT
;
741 case 's': /* string or substring */
742 strncpy (string_value
, optarg
, sizeof (string_value
) - 1);
743 string_value
[sizeof (string_value
) - 1] = 0;
744 eval_method
[jj
++] = CRIT_STRING
;
747 case 'R': /* regex */
749 case 'r': /* regex */
750 cflags
|= REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
;
751 strncpy (regex_expect
, optarg
, sizeof (regex_expect
) - 1);
752 regex_expect
[sizeof (regex_expect
) - 1] = 0;
753 errcode
= regcomp (&preg
, regex_expect
, cflags
);
755 regerror (errcode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
756 printf (_("Could Not Compile Regular Expression"));
759 eval_method
[jj
++] = CRIT_REGEX
;
764 case 'd': /* delimiter */
765 delimiter
= strscpy (delimiter
, optarg
);
767 case 'D': /* output-delimiter */
768 output_delim
= strscpy (output_delim
, optarg
);
770 case 'l': /* label */
772 if (nlabels
> labels_size
) {
774 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
776 die (STATE_UNKNOWN
, _("Could not reallocate labels[%d]"), (int)nlabels
);
778 labels
[nlabels
- 1] = optarg
;
779 ptr
= thisarg (optarg
);
780 labels
[nlabels
- 1] = ptr
;
782 labels
[nlabels
- 1] = ptr
+ 1;
783 while (ptr
&& (ptr
= nextarg (ptr
))) {
785 if (nlabels
> labels_size
) {
787 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
789 die (STATE_UNKNOWN
, _("Could not reallocate labels\n"));
793 labels
[nlabels
- 1] = ptr
+ 1;
795 labels
[nlabels
- 1] = ptr
;
798 case 'u': /* units */
801 if (nunits
> unitv_size
) {
803 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
805 die (STATE_UNKNOWN
, _("Could not reallocate units [%d]\n"), (int)nunits
);
807 unitv
[nunits
- 1] = optarg
;
808 ptr
= thisarg (optarg
);
809 unitv
[nunits
- 1] = ptr
;
811 unitv
[nunits
- 1] = ptr
+ 1;
812 while (ptr
&& (ptr
= nextarg (ptr
))) {
813 if (nunits
> unitv_size
) {
815 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
817 die (STATE_UNKNOWN
, _("Could not realloc() units\n"));
822 unitv
[nunits
- 1] = ptr
+ 1;
824 unitv
[nunits
- 1] = ptr
;
827 case L_CALCULATE_RATE
:
828 if(calculate_rate
==0)
829 np_enable_state(NULL
, 1);
832 case L_RATE_MULTIPLIER
:
833 if(!is_integer(optarg
)||((rate_multiplier
=atoi(optarg
))<=0))
834 usage2(_("Rate multiplier must be a positive integer"),optarg
);
836 case L_INVERT_SEARCH
:
845 if (server_address
== NULL
)
846 server_address
= argv
[optind
];
848 if (community
== NULL
)
849 community
= strdup (DEFAULT_COMMUNITY
);
851 return validate_arguments ();
855 /******************************************************************************
859 <title>validate_arguments</title>
861 <para>&PROTO_validate_arguments;</para>
863 <para>Checks to see if the default miblist needs to be loaded. Also verifies
864 the authentication and authorization combinations based on protocol version
871 ******************************************************************************/
876 validate_arguments ()
878 /* check whether to load locally installed MIBS (CPU/disk intensive) */
879 if (miblist
== NULL
) {
880 if ( needmibs
== TRUE
) {
881 miblist
= strdup (DEFAULT_MIBLIST
);
883 miblist
= ""; /* don't read any mib files for numeric oids */
887 /* Check server_address is given */
888 if (server_address
== NULL
)
889 die(STATE_UNKNOWN
, _("No host specified\n"));
891 /* Check oid is given */
893 die(STATE_UNKNOWN
, _("No OIDs specified\n"));
896 xasprintf(&proto
, DEFAULT_PROTOCOL
);
898 if ((strcmp(proto
,"1") == 0) || (strcmp(proto
, "2c")==0)) { /* snmpv1 or snmpv2c */
900 authpriv
= calloc (numauthpriv
, sizeof (char *));
901 authpriv
[0] = strdup ("-c");
902 authpriv
[1] = strdup (community
);
904 else if ( strcmp (proto
, "3") == 0 ) { /* snmpv3 args */
905 if (seclevel
== NULL
)
906 xasprintf(&seclevel
, "noAuthNoPriv");
908 if (strcmp(seclevel
, "noAuthNoPriv") == 0) {
910 authpriv
= calloc (numauthpriv
, sizeof (char *));
911 authpriv
[0] = strdup ("-l");
912 authpriv
[1] = strdup ("noAuthNoPriv");
914 if (! ( (strcmp(seclevel
, "authNoPriv")==0) || (strcmp(seclevel
, "authPriv")==0) ) ) {
915 usage2 (_("Invalid seclevel"), seclevel
);
918 if (authproto
== NULL
)
919 xasprintf(&authproto
, DEFAULT_AUTH_PROTOCOL
);
922 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "secname");
924 if (authpasswd
== NULL
)
925 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "authpasswd");
927 if ( strcmp(seclevel
, "authNoPriv") == 0 ) {
929 authpriv
= calloc (numauthpriv
, sizeof (char *));
930 authpriv
[0] = strdup ("-l");
931 authpriv
[1] = strdup ("authNoPriv");
932 authpriv
[2] = strdup ("-a");
933 authpriv
[3] = strdup (authproto
);
934 authpriv
[4] = strdup ("-u");
935 authpriv
[5] = strdup (secname
);
936 authpriv
[6] = strdup ("-A");
937 authpriv
[7] = strdup (authpasswd
);
938 } else if ( strcmp(seclevel
, "authPriv") == 0 ) {
939 if (privproto
== NULL
)
940 xasprintf(&privproto
, DEFAULT_PRIV_PROTOCOL
);
942 if (privpasswd
== NULL
)
943 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "privpasswd");
946 authpriv
= calloc (numauthpriv
, sizeof (char *));
947 authpriv
[0] = strdup ("-l");
948 authpriv
[1] = strdup ("authPriv");
949 authpriv
[2] = strdup ("-a");
950 authpriv
[3] = strdup (authproto
);
951 authpriv
[4] = strdup ("-u");
952 authpriv
[5] = strdup (secname
);
953 authpriv
[6] = strdup ("-A");
954 authpriv
[7] = strdup (authpasswd
);
955 authpriv
[8] = strdup ("-x");
956 authpriv
[9] = strdup (privproto
);
957 authpriv
[10] = strdup ("-X");
958 authpriv
[11] = strdup (privpasswd
);
964 usage2 (_("Invalid SNMP version"), proto
);
972 /* trim leading whitespace
973 if there is a leading quote, make sure it balances */
978 str
+= strspn (str
, " \t\r\n"); /* trim any leading whitespace */
979 if (str
[0] == '\'') { /* handle SIMPLE quoted strings */
980 if (strlen (str
) == 1 || !strstr (str
+ 1, "'"))
981 die (STATE_UNKNOWN
, _("Unbalanced quotes\n"));
988 /* if there's a leading quote, advance to the trailing quote
989 set the trailing quote to '\x0'
990 if the string continues, advance beyond the comma */
995 if (str
[0] == '\'') {
997 if (strlen (str
) > 1) {
998 str
= strstr (str
+ 1, "'");
1005 if (str
[0] == ',') {
1007 if (strlen (str
) > 1) {
1014 if ((str
= strstr (str
, ",")) && strlen (str
) > 1) {
1026 print_revision (progname
, NP_VERSION
);
1028 printf (COPYRIGHT
, copyright
, email
);
1030 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1036 printf (UT_HELP_VRSN
);
1037 printf (UT_EXTRA_OPTS
);
1039 printf (UT_HOST_PORT
, 'p', DEFAULT_PORT
);
1041 /* SNMP and Authentication Protocol */
1042 printf (" %s\n", "-n, --next");
1043 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1044 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1045 printf (" %s\n", _("SNMP protocol version"));
1046 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1047 printf (" %s\n", _("SNMPv3 securityLevel"));
1048 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
1049 printf (" %s\n", _("SNMPv3 auth proto"));
1050 printf (" %s\n", "-x, --privproto=[DES|AES]");
1051 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
1053 /* Authentication Tokens*/
1054 printf (" %s\n", "-C, --community=STRING");
1055 printf (" %s ", _("Optional community string for SNMP communication"));
1056 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY
);
1057 printf (" %s\n", "-U, --secname=USERNAME");
1058 printf (" %s\n", _("SNMPv3 username"));
1059 printf (" %s\n", "-A, --authpassword=PASSWORD");
1060 printf (" %s\n", _("SNMPv3 authentication password"));
1061 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1062 printf (" %s\n", _("SNMPv3 privacy password"));
1065 printf (" %s\n", "-o, --oid=OID(s)");
1066 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1067 printf (" %s\n", "-m, --miblist=STRING");
1068 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1069 printf (" %s\n", _("for symbolic OIDs.)"));
1070 printf (" %s\n", "-d, --delimiter=STRING");
1071 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER
);
1072 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1073 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1075 /* Tests Against Integers */
1076 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1077 printf (" %s\n", _("Warning threshold range(s)"));
1078 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1079 printf (" %s\n", _("Critical threshold range(s)"));
1080 printf (" %s\n", "--rate");
1081 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1082 printf (" %s\n", "--rate-multiplier");
1083 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1085 /* Tests Against Strings */
1086 printf (" %s\n", "-s, --string=STRING");
1087 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1088 printf (" %s\n", "-r, --ereg=REGEX");
1089 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1090 printf (" %s\n", "-R, --eregi=REGEX");
1091 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1092 printf (" %s\n", "--invert-search");
1093 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1095 /* Output Formatting */
1096 printf (" %s\n", "-l, --label=STRING");
1097 printf (" %s\n", _("Prefix label for output from plugin"));
1098 printf (" %s\n", "-u, --units=STRING");
1099 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1100 printf (" %s\n", "-D, --output-delimiter=STRING");
1101 printf (" %s\n", _("Separates output on multiple OID requests"));
1103 printf (UT_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
1104 printf (" %s\n", "-e, --retries=INTEGER");
1105 printf (" %s\n", _("Number of retries to be used in the requests"));
1107 printf (" %s\n", "-O, --perf-oids");
1108 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1110 printf (UT_VERBOSE
);
1113 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1114 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1115 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1118 printf ("%s\n", _("Notes:"));
1119 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1120 printf (" %s %i %s\n", _("list (lists with internal spaces must be quoted). Maximum:"), MAX_OIDS
, _("OIDs."));
1122 printf(" -%s", UT_THRESHOLDS_NOTES
);
1124 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1125 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1126 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1127 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1130 printf("%s\n", _("Rate Calculation:"));
1131 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1132 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1133 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1134 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1135 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1136 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1137 printf(" %s\n", _("changing the arguments will create a new state file."));
1139 printf (UT_SUPPORT
);
1147 printf ("%s\n", _("Usage:"));
1148 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname
);
1149 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1150 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1151 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1152 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");