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 ("-t");
281 xasprintf (&command_line
[2], "%d", timeout_interval
);
282 command_line
[3] = strdup ("-r");
283 xasprintf (&command_line
[4], "%d", retries
);
284 command_line
[5] = strdup ("-m");
285 command_line
[6] = strdup (miblist
);
286 command_line
[7] = "-v";
287 command_line
[8] = strdup (proto
);
289 for (i
= 0; i
< numauthpriv
; i
++) {
290 command_line
[9 + i
] = authpriv
[i
];
293 xasprintf (&command_line
[9 + numauthpriv
], "%s:%s", server_address
, port
);
295 /* This is just for display purposes, so it can remain a string */
296 xasprintf(&cl_hidden_auth
, "%s -t %d -r %d -m %s -v %s %s %s:%s",
297 snmpcmd
, timeout_interval
, retries
, strlen(miblist
) ? miblist
: "''", proto
, "[authpriv]",
298 server_address
, port
);
300 for (i
= 0; i
< numoids
; i
++) {
301 command_line
[9 + numauthpriv
+ 1 + i
] = oids
[i
];
302 xasprintf(&cl_hidden_auth
, "%s %s", cl_hidden_auth
, oids
[i
]);
305 command_line
[9 + numauthpriv
+ 1 + numoids
] = NULL
;
308 printf ("%s\n", cl_hidden_auth
);
310 /* Run the command */
311 return_code
= cmd_run_array (command_line
, &chld_out
, &chld_err
, 0);
313 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
314 only return state unknown if return code is non zero or there is no stdout.
315 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
317 if (return_code
!= 0)
319 if (chld_out
.lines
== 0)
321 if (external_error
) {
322 if (chld_err
.lines
> 0) {
323 printf (_("External command error: %s\n"), chld_err
.line
[0]);
324 for (i
= 1; i
< chld_err
.lines
; i
++) {
325 printf ("%s\n", chld_err
.line
[i
]);
328 printf(_("External command error with no output (return code: %d)\n"), return_code
);
330 exit (STATE_UNKNOWN
);
334 for (i
= 0; i
< chld_out
.lines
; i
++) {
335 printf ("%s\n", chld_out
.line
[i
]);
339 for (line
=0, i
=0; line
< chld_out
.lines
; line
++, i
++) {
345 ptr
= chld_out
.line
[line
];
346 oidname
= strpcpy (oidname
, ptr
, delimiter
);
347 response
= strstr (ptr
, delimiter
);
348 if (response
== NULL
)
352 printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i
+1, line
+1, oidname
, response
);
355 /* Clean up type array - Sol10 does not necessarily zero it out */
356 bzero(type
, sizeof(type
));
359 /* We strip out the datatype indicator for PHBs */
360 if (strstr (response
, "Gauge: ")) {
361 show
= strstr (response
, "Gauge: ") + 7;
363 else if (strstr (response
, "Gauge32: ")) {
364 show
= strstr (response
, "Gauge32: ") + 9;
366 else if (strstr (response
, "Counter32: ")) {
367 show
= strstr (response
, "Counter32: ") + 11;
372 else if (strstr (response
, "Counter64: ")) {
373 show
= strstr (response
, "Counter64: ") + 11;
378 else if (strstr (response
, "INTEGER: ")) {
379 show
= strstr (response
, "INTEGER: ") + 9;
381 else if (strstr (response
, "STRING: ")) {
382 show
= strstr (response
, "STRING: ") + 8;
385 /* Get the rest of the string on multi-line strings */
387 COUNT_SEQ(ptr
, bk_count
, dq_count
)
388 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
390 GOBBLE_TOS(ptr
, "\n\"\\")
391 COUNT_SEQ(ptr
, bk_count
, dq_count
)
394 if (dq_count
) { /* unfinished line */
395 /* copy show verbatim first */
396 if (!mult_resp
) mult_resp
= strdup("");
397 xasprintf (&mult_resp
, "%s%s:\n%s\n", mult_resp
, oids
[i
], show
);
398 /* then strip out unmatched double-quote from single-line output */
399 if (show
[0] == '"') show
++;
401 /* Keep reading until we match end of double-quoted string */
402 for (line
++; line
< chld_out
.lines
; line
++) {
403 ptr
= chld_out
.line
[line
];
404 xasprintf (&mult_resp
, "%s%s\n", mult_resp
, ptr
);
406 COUNT_SEQ(ptr
, bk_count
, dq_count
)
407 while (dq_count
&& ptr
[0] != '\n' && ptr
[0] != '\0') {
409 GOBBLE_TOS(ptr
, "\n\"\\")
410 COUNT_SEQ(ptr
, bk_count
, dq_count
)
412 /* Break for loop before next line increment when done */
413 if (!dq_count
) break;
418 else if (strstr (response
, "Timeticks: ")) {
419 show
= strstr (response
, "Timeticks: ");
424 iresult
= STATE_DEPENDENT
;
426 /* Process this block for numeric comparisons */
427 /* Make some special values,like Timeticks numeric only if a threshold is defined */
428 if (thlds
[i
]->warning
|| thlds
[i
]->critical
|| calculate_rate
) {
429 ptr
= strpbrk (show
, "0123456789");
431 die (STATE_UNKNOWN
,_("No valid data returned (%s)\n"), show
);
432 response_value
[i
] = strtod (ptr
, NULL
);
435 if (previous_state
!=NULL
) {
436 duration
= current_time
-previous_state
->time
;
438 die(STATE_UNKNOWN
,_("Time duration between plugin calls is invalid"));
439 temp_double
= response_value
[i
]-previous_value
[i
];
440 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
442 if(temp_double
<(double)0.0)
443 temp_double
+=(double)4294967296.0; /* 2^32 */
444 if(temp_double
<(double)0.0)
445 temp_double
+=(double)18446744069414584320.0; /* 2^64-2^32 */;
447 /* Convert to per second, then use multiplier */
448 temp_double
= temp_double
/duration
*rate_multiplier
;
449 iresult
= get_status(temp_double
, thlds
[i
]);
450 xasprintf (&show
, conv
, temp_double
);
453 iresult
= get_status(response_value
[i
], thlds
[i
]);
454 xasprintf (&show
, conv
, response_value
[i
]);
458 /* Process this block for string matching */
459 else if (eval_method
[i
] & CRIT_STRING
) {
460 if (strcmp (show
, string_value
))
461 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
463 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
466 /* Process this block for regex matching */
467 else if (eval_method
[i
] & CRIT_REGEX
) {
468 excode
= regexec (&preg
, response
, 10, pmatch
, eflags
);
470 iresult
= (invert_search
==0) ? STATE_OK
: STATE_CRITICAL
;
472 else if (excode
!= REG_NOMATCH
) {
473 regerror (excode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
474 printf (_("Execute Error: %s\n"), errbuf
);
475 exit (STATE_CRITICAL
);
478 iresult
= (invert_search
==0) ? STATE_CRITICAL
: STATE_OK
;
482 /* Process this block for existence-nonexistence checks */
483 /* TV: Should this be outside of this else block? */
485 if (eval_method
[i
] & CRIT_PRESENT
)
486 iresult
= STATE_CRITICAL
;
487 else if (eval_method
[i
] & WARN_PRESENT
)
488 iresult
= STATE_WARNING
;
489 else if (response
&& iresult
== STATE_DEPENDENT
)
493 /* Result is the worst outcome of all the OIDs tested */
494 result
= max_state (result
, iresult
);
496 /* Prepend a label for this OID if there is one */
497 if (nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
498 xasprintf (&outbuff
, "%s%s%s %s%s%s", outbuff
,
499 (i
== 0) ? " " : output_delim
,
500 labels
[i
], mark (iresult
), show
, mark (iresult
));
502 xasprintf (&outbuff
, "%s%s%s%s%s", outbuff
, (i
== 0) ? " " : output_delim
,
503 mark (iresult
), show
, mark (iresult
));
505 /* Append a unit string for this OID if there is one */
506 if (nunits
> (size_t)0 && (size_t)i
< nunits
&& unitv
[i
] != NULL
)
507 xasprintf (&outbuff
, "%s %s", outbuff
, unitv
[i
]);
509 /* Write perfdata with whatever can be parsed by strtod, if possible */
513 if (perf_labels
&& nlabels
>= (size_t)1 && (size_t)i
< nlabels
&& labels
[i
] != NULL
)
514 temp_string
=labels
[i
];
517 if (strpbrk (temp_string
, " ='\"") == NULL
) {
518 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
520 if (strpbrk (temp_string
, "'") == NULL
) {
525 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
526 strncat(perfstr
, temp_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
527 strncat(perfstr
, quote_string
, sizeof(perfstr
)-strlen(perfstr
)-1);
529 strncat(perfstr
, "=", sizeof(perfstr
)-strlen(perfstr
)-1);
530 len
= sizeof(perfstr
)-strlen(perfstr
)-1;
531 strncat(perfstr
, show
, len
>ptr
-show
? ptr
-show
: len
);
534 strncat(perfstr
, type
, sizeof(perfstr
)-strlen(perfstr
)-1);
535 strncat(perfstr
, " ", sizeof(perfstr
)-strlen(perfstr
)-1);
540 /* Save state data, as all data collected now */
543 state_string
=malloc(string_length
);
544 if(state_string
==NULL
)
545 die(STATE_UNKNOWN
, _("Cannot malloc"));
548 for(i
=0; i
<total_oids
; i
++) {
549 xasprintf(&temp_string
,"%.0f",response_value
[i
]);
550 if(temp_string
==NULL
)
551 die(STATE_UNKNOWN
,_("Cannot asprintf()"));
552 response_length
= strlen(temp_string
);
553 if(current_length
+response_length
>string_length
) {
554 string_length
=current_length
+1024;
555 state_string
=realloc(state_string
,string_length
);
556 if(state_string
==NULL
)
557 die(STATE_UNKNOWN
, _("Cannot realloc()"));
559 strcpy(&state_string
[current_length
],temp_string
);
560 current_length
=current_length
+response_length
;
561 state_string
[current_length
]=':';
565 state_string
[--current_length
]='\0';
567 printf("State string=%s\n",state_string
);
569 /* This is not strictly the same as time now, but any subtle variations will cancel out */
570 np_state_write_string(current_time
, state_string
);
571 if(previous_state
==NULL
) {
572 /* Or should this be highest state? */
573 die( STATE_OK
, _("No previous data to calculate rate - assume okay" ) );
577 printf ("%s %s -%s %s\n", label
, state_text (result
), outbuff
, perfstr
);
578 if (mult_resp
) printf ("%s", mult_resp
);
585 /* process command-line arguments */
587 process_arguments (int argc
, char **argv
)
591 int j
= 0, jj
= 0, ii
= 0;
594 static struct option longopts
[] = {
596 {"community", required_argument
, 0, 'C'},
597 {"oid", required_argument
, 0, 'o'},
598 {"object", required_argument
, 0, 'o'},
599 {"delimiter", required_argument
, 0, 'd'},
600 {"output-delimiter", required_argument
, 0, 'D'},
601 {"string", required_argument
, 0, 's'},
602 {"timeout", required_argument
, 0, 't'},
603 {"regex", required_argument
, 0, 'r'},
604 {"ereg", required_argument
, 0, 'r'},
605 {"eregi", required_argument
, 0, 'R'},
606 {"label", required_argument
, 0, 'l'},
607 {"units", required_argument
, 0, 'u'},
608 {"port", required_argument
, 0, 'p'},
609 {"retries", required_argument
, 0, 'e'},
610 {"miblist", required_argument
, 0, 'm'},
611 {"protocol", required_argument
, 0, 'P'},
612 {"seclevel", required_argument
, 0, 'L'},
613 {"secname", required_argument
, 0, 'U'},
614 {"authproto", required_argument
, 0, 'a'},
615 {"privproto", required_argument
, 0, 'x'},
616 {"authpasswd", required_argument
, 0, 'A'},
617 {"privpasswd", required_argument
, 0, 'X'},
618 {"next", no_argument
, 0, 'n'},
619 {"rate", no_argument
, 0, L_CALCULATE_RATE
},
620 {"rate-multiplier", required_argument
, 0, L_RATE_MULTIPLIER
},
621 {"invert-search", no_argument
, 0, L_INVERT_SEARCH
},
622 {"perf-oids", no_argument
, 0, 'O'},
629 /* reverse compatibility for very old non-POSIX usage forms */
630 for (c
= 1; c
< argc
; c
++) {
631 if (strcmp ("-to", argv
[c
]) == 0)
632 strcpy (argv
[c
], "-t");
633 if (strcmp ("-wv", argv
[c
]) == 0)
634 strcpy (argv
[c
], "-w");
635 if (strcmp ("-cv", argv
[c
]) == 0)
636 strcpy (argv
[c
], "-c");
640 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:",
643 if (c
== -1 || c
== EOF
)
647 case '?': /* usage */
652 case 'V': /* version */
653 print_revision (progname
, NP_VERSION
);
655 case 'v': /* verbose */
659 /* Connection info */
660 case 'C': /* group or community */
663 case 'H': /* Host or server */
664 server_address
= optarg
;
666 case 'p': /* TCP port number */
669 case 'm': /* List of MIBS */
672 case 'n': /* usesnmpgetnext */
673 usesnmpgetnext
= TRUE
;
675 case 'P': /* SNMP protocol version */
678 case 'L': /* security level */
681 case 'U': /* security username */
684 case 'a': /* auth protocol */
687 case 'x': /* priv protocol */
690 case 'A': /* auth passwd */
693 case 'X': /* priv passwd */
696 case 't': /* timeout period */
697 if (!is_integer (optarg
))
698 usage2 (_("Timeout interval must be a positive integer"), optarg
);
700 timeout_interval
= atoi (optarg
);
703 /* Test parameters */
704 case 'c': /* critical threshold */
705 critical_thresholds
= optarg
;
707 case 'w': /* warning threshold */
708 warning_thresholds
= optarg
;
710 case 'e': /* PRELIMINARY - may change */
711 case 'E': /* PRELIMINARY - may change */
712 if (!is_integer (optarg
))
713 usage2 (_("Retries interval must be a positive integer"), optarg
);
715 retries
= atoi(optarg
);
717 case 'o': /* object identifier */
718 if ( strspn( optarg
, "0123456789.," ) != strlen( optarg
) ) {
720 * we have something other than digits, periods and comas,
721 * so we have a mib variable, rather than just an SNMP OID,
722 * so we have to actually read the mib files
726 if (!oids
) oids
= calloc(MAX_OIDS
, sizeof (char *));
727 for (ptr
= strtok(optarg
, ", "); ptr
!= NULL
&& j
< MAX_OIDS
; ptr
= strtok(NULL
, ", "), j
++) {
728 oids
[j
] = strdup(ptr
);
731 if (c
== 'E' || c
== 'e') {
736 eval_method
[j
+1] |= WARN_PRESENT
;
738 eval_method
[j
+1] |= CRIT_PRESENT
;
740 case 's': /* string or substring */
741 strncpy (string_value
, optarg
, sizeof (string_value
) - 1);
742 string_value
[sizeof (string_value
) - 1] = 0;
743 eval_method
[jj
++] = CRIT_STRING
;
746 case 'R': /* regex */
748 case 'r': /* regex */
749 cflags
|= REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
;
750 strncpy (regex_expect
, optarg
, sizeof (regex_expect
) - 1);
751 regex_expect
[sizeof (regex_expect
) - 1] = 0;
752 errcode
= regcomp (&preg
, regex_expect
, cflags
);
754 regerror (errcode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
755 printf (_("Could Not Compile Regular Expression"));
758 eval_method
[jj
++] = CRIT_REGEX
;
763 case 'd': /* delimiter */
764 delimiter
= strscpy (delimiter
, optarg
);
766 case 'D': /* output-delimiter */
767 output_delim
= strscpy (output_delim
, optarg
);
769 case 'l': /* label */
771 if (nlabels
> labels_size
) {
773 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
775 die (STATE_UNKNOWN
, _("Could not reallocate labels[%d]"), (int)nlabels
);
777 labels
[nlabels
- 1] = optarg
;
778 ptr
= thisarg (optarg
);
779 labels
[nlabels
- 1] = ptr
;
781 labels
[nlabels
- 1] = ptr
+ 1;
782 while (ptr
&& (ptr
= nextarg (ptr
))) {
784 if (nlabels
> labels_size
) {
786 labels
= realloc (labels
, labels_size
* sizeof(*labels
));
788 die (STATE_UNKNOWN
, _("Could not reallocate labels\n"));
792 labels
[nlabels
- 1] = ptr
+ 1;
794 labels
[nlabels
- 1] = ptr
;
797 case 'u': /* units */
800 if (nunits
> unitv_size
) {
802 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
804 die (STATE_UNKNOWN
, _("Could not reallocate units [%d]\n"), (int)nunits
);
806 unitv
[nunits
- 1] = optarg
;
807 ptr
= thisarg (optarg
);
808 unitv
[nunits
- 1] = ptr
;
810 unitv
[nunits
- 1] = ptr
+ 1;
811 while (ptr
&& (ptr
= nextarg (ptr
))) {
812 if (nunits
> unitv_size
) {
814 unitv
= realloc (unitv
, unitv_size
* sizeof(*unitv
));
816 die (STATE_UNKNOWN
, _("Could not realloc() units\n"));
821 unitv
[nunits
- 1] = ptr
+ 1;
823 unitv
[nunits
- 1] = ptr
;
826 case L_CALCULATE_RATE
:
827 if(calculate_rate
==0)
828 np_enable_state(NULL
, 1);
831 case L_RATE_MULTIPLIER
:
832 if(!is_integer(optarg
)||((rate_multiplier
=atoi(optarg
))<=0))
833 usage2(_("Rate multiplier must be a positive integer"),optarg
);
835 case L_INVERT_SEARCH
:
844 if (server_address
== NULL
)
845 server_address
= argv
[optind
];
847 if (community
== NULL
)
848 community
= strdup (DEFAULT_COMMUNITY
);
850 return validate_arguments ();
854 /******************************************************************************
858 <title>validate_arguments</title>
860 <para>&PROTO_validate_arguments;</para>
862 <para>Checks to see if the default miblist needs to be loaded. Also verifies
863 the authentication and authorization combinations based on protocol version
870 ******************************************************************************/
875 validate_arguments ()
877 /* check whether to load locally installed MIBS (CPU/disk intensive) */
878 if (miblist
== NULL
) {
879 if ( needmibs
== TRUE
) {
880 miblist
= strdup (DEFAULT_MIBLIST
);
882 miblist
= ""; /* don't read any mib files for numeric oids */
886 /* Check server_address is given */
887 if (server_address
== NULL
)
888 die(STATE_UNKNOWN
, _("No host specified\n"));
890 /* Check oid is given */
892 die(STATE_UNKNOWN
, _("No OIDs specified\n"));
895 xasprintf(&proto
, DEFAULT_PROTOCOL
);
897 if ((strcmp(proto
,"1") == 0) || (strcmp(proto
, "2c")==0)) { /* snmpv1 or snmpv2c */
899 authpriv
= calloc (numauthpriv
, sizeof (char *));
900 authpriv
[0] = strdup ("-c");
901 authpriv
[1] = strdup (community
);
903 else if ( strcmp (proto
, "3") == 0 ) { /* snmpv3 args */
904 if (seclevel
== NULL
)
905 xasprintf(&seclevel
, "noAuthNoPriv");
907 if (strcmp(seclevel
, "noAuthNoPriv") == 0) {
909 authpriv
= calloc (numauthpriv
, sizeof (char *));
910 authpriv
[0] = strdup ("-l");
911 authpriv
[1] = strdup ("noAuthNoPriv");
913 if (! ( (strcmp(seclevel
, "authNoPriv")==0) || (strcmp(seclevel
, "authPriv")==0) ) ) {
914 usage2 (_("Invalid seclevel"), seclevel
);
917 if (authproto
== NULL
)
918 xasprintf(&authproto
, DEFAULT_AUTH_PROTOCOL
);
921 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "secname");
923 if (authpasswd
== NULL
)
924 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "authpasswd");
926 if ( strcmp(seclevel
, "authNoPriv") == 0 ) {
928 authpriv
= calloc (numauthpriv
, sizeof (char *));
929 authpriv
[0] = strdup ("-l");
930 authpriv
[1] = strdup ("authNoPriv");
931 authpriv
[2] = strdup ("-a");
932 authpriv
[3] = strdup (authproto
);
933 authpriv
[4] = strdup ("-u");
934 authpriv
[5] = strdup (secname
);
935 authpriv
[6] = strdup ("-A");
936 authpriv
[7] = strdup (authpasswd
);
937 } else if ( strcmp(seclevel
, "authPriv") == 0 ) {
938 if (privproto
== NULL
)
939 xasprintf(&privproto
, DEFAULT_PRIV_PROTOCOL
);
941 if (privpasswd
== NULL
)
942 die(STATE_UNKNOWN
, _("Required parameter: %s\n"), "privpasswd");
945 authpriv
= calloc (numauthpriv
, sizeof (char *));
946 authpriv
[0] = strdup ("-l");
947 authpriv
[1] = strdup ("authPriv");
948 authpriv
[2] = strdup ("-a");
949 authpriv
[3] = strdup (authproto
);
950 authpriv
[4] = strdup ("-u");
951 authpriv
[5] = strdup (secname
);
952 authpriv
[6] = strdup ("-A");
953 authpriv
[7] = strdup (authpasswd
);
954 authpriv
[8] = strdup ("-x");
955 authpriv
[9] = strdup (privproto
);
956 authpriv
[10] = strdup ("-X");
957 authpriv
[11] = strdup (privpasswd
);
963 usage2 (_("Invalid SNMP version"), proto
);
971 /* trim leading whitespace
972 if there is a leading quote, make sure it balances */
977 str
+= strspn (str
, " \t\r\n"); /* trim any leading whitespace */
978 if (str
[0] == '\'') { /* handle SIMPLE quoted strings */
979 if (strlen (str
) == 1 || !strstr (str
+ 1, "'"))
980 die (STATE_UNKNOWN
, _("Unbalanced quotes\n"));
987 /* if there's a leading quote, advance to the trailing quote
988 set the trailing quote to '\x0'
989 if the string continues, advance beyond the comma */
994 if (str
[0] == '\'') {
996 if (strlen (str
) > 1) {
997 str
= strstr (str
+ 1, "'");
1004 if (str
[0] == ',') {
1006 if (strlen (str
) > 1) {
1013 if ((str
= strstr (str
, ",")) && strlen (str
) > 1) {
1025 print_revision (progname
, NP_VERSION
);
1027 printf (COPYRIGHT
, copyright
, email
);
1029 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1035 printf (UT_HELP_VRSN
);
1036 printf (UT_EXTRA_OPTS
);
1038 printf (UT_HOST_PORT
, 'p', DEFAULT_PORT
);
1040 /* SNMP and Authentication Protocol */
1041 printf (" %s\n", "-n, --next");
1042 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1043 printf (" %s\n", "-P, --protocol=[1|2c|3]");
1044 printf (" %s\n", _("SNMP protocol version"));
1045 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1046 printf (" %s\n", _("SNMPv3 securityLevel"));
1047 printf (" %s\n", "-a, --authproto=[MD5|SHA]");
1048 printf (" %s\n", _("SNMPv3 auth proto"));
1049 printf (" %s\n", "-x, --privproto=[DES|AES]");
1050 printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
1052 /* Authentication Tokens*/
1053 printf (" %s\n", "-C, --community=STRING");
1054 printf (" %s ", _("Optional community string for SNMP communication"));
1055 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY
);
1056 printf (" %s\n", "-U, --secname=USERNAME");
1057 printf (" %s\n", _("SNMPv3 username"));
1058 printf (" %s\n", "-A, --authpassword=PASSWORD");
1059 printf (" %s\n", _("SNMPv3 authentication password"));
1060 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1061 printf (" %s\n", _("SNMPv3 privacy password"));
1064 printf (" %s\n", "-o, --oid=OID(s)");
1065 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1066 printf (" %s\n", "-m, --miblist=STRING");
1067 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1068 printf (" %s\n", _("for symbolic OIDs.)"));
1069 printf (" %s\n", "-d, --delimiter=STRING");
1070 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER
);
1071 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1072 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1074 /* Tests Against Integers */
1075 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
1076 printf (" %s\n", _("Warning threshold range(s)"));
1077 printf (" %s\n", "-c, --critical=THRESHOLD(s)");
1078 printf (" %s\n", _("Critical threshold range(s)"));
1079 printf (" %s\n", "--rate");
1080 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1081 printf (" %s\n", "--rate-multiplier");
1082 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1084 /* Tests Against Strings */
1085 printf (" %s\n", "-s, --string=STRING");
1086 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1087 printf (" %s\n", "-r, --ereg=REGEX");
1088 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1089 printf (" %s\n", "-R, --eregi=REGEX");
1090 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1091 printf (" %s\n", "--invert-search");
1092 printf (" %s\n", _("Invert search result (CRITICAL if found)"));
1094 /* Output Formatting */
1095 printf (" %s\n", "-l, --label=STRING");
1096 printf (" %s\n", _("Prefix label for output from plugin"));
1097 printf (" %s\n", "-u, --units=STRING");
1098 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1099 printf (" %s\n", "-D, --output-delimiter=STRING");
1100 printf (" %s\n", _("Separates output on multiple OID requests"));
1102 printf (UT_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
1103 printf (" %s\n", "-e, --retries=INTEGER");
1104 printf (" %s\n", _("Number of retries to be used in the requests"));
1106 printf (" %s\n", "-O, --perf-oids");
1107 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1109 printf (UT_VERBOSE
);
1112 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1113 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1114 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1117 printf ("%s\n", _("Notes:"));
1118 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1119 printf (" %s %i %s\n", _("list (lists with internal spaces must be quoted). Maximum:"), MAX_OIDS
, _("OIDs."));
1121 printf(" -%s", UT_THRESHOLDS_NOTES
);
1123 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1124 printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
1125 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1126 printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
1129 printf("%s\n", _("Rate Calculation:"));
1130 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1131 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1132 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1133 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1134 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1135 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1136 printf(" %s\n", _("changing the arguments will create a new state file."));
1138 printf (UT_SUPPORT
);
1146 printf ("%s\n", _("Usage:"));
1147 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname
);
1148 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1149 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1150 printf ("[-m miblist] [-P snmp version] [-L seclevel] [-U secname] [-a authproto]\n");
1151 printf ("[-A authpasswd] [-x privproto] [-X privpasswd]\n");