check_procs: Assume we have stat()
[monitoring-plugins.git] / plugins / check_snmp.c
blob7c5d0ec560cb56f7dd2f58700ea44ea3af9ba01f
1 /*****************************************************************************
2 *
3 * Nagios check_snmp plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2007 Nagios Plugins Development Team
7 *
8 * Description:
9 *
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";
35 #include "common.h"
36 #include "utils.h"
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?"*":"")
52 #define CHECK_UNDEF 0
53 #define CRIT_PRESENT 1
54 #define CRIT_STRING 2
55 #define CRIT_REGEX 4
56 #define WARN_PRESENT 8
57 #define WARN_STRING 16
58 #define WARN_REGEX 32
60 #define MAX_OIDS 8
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
68 * characters in s */
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)
71 * from c[0] */
72 #define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
73 case '\\': \
74 if (bk) bk--; \
75 else bk++; \
76 break; \
77 case '"': \
78 if (!dq) { dq++; } \
79 else if(!bk) { dq--; } \
80 else { bk--; } \
81 break; \
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);
93 #include "regex.h"
94 char regex_expect[MAX_INPUT_BUFFER] = "";
95 regex_t preg;
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;
100 int eflags = 0;
101 int errcode, excode;
103 char *server_address = NULL;
104 char *community = NULL;
105 char **authpriv = NULL;
106 char *proto = 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;
113 char **oids = NULL;
114 char *label;
115 char *units;
116 char *port;
117 char *snmpcmd;
118 char string_value[MAX_INPUT_BUFFER] = "";
119 int invert_search=0;
120 char **labels = NULL;
121 char **unitv = NULL;
122 size_t nlabels = 0;
123 size_t labels_size = 8;
124 size_t nunits = 0;
125 size_t unitv_size = 8;
126 int numoids = 0;
127 int numauthpriv = 0;
128 int verbose = 0;
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];
134 int retries = 0;
135 int eval_method[MAX_OIDS];
136 char *delimiter;
137 char *output_delim;
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];
144 int perf_labels = 1;
147 static char *fix_snmp_range(char *th)
149 double left, right;
150 char *colon, *ret;
151 if (!(colon = strchr(th, ':')))
152 return th;
153 *colon = 0;
155 left = strtod(th, NULL);
156 right = strtod(colon + 1, NULL);
157 if (right >= left) {
158 return th;
160 ret = malloc(strlen(th) + strlen(colon + 1) + 2);
161 sprintf(ret, "@%s:%s", colon + 1, th);
162 free(th);
163 return ret;
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;
173 int return_code = 0;
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;
180 char *outbuff;
181 char *ptr = NULL;
182 char *show = NULL;
183 char *th_warn=NULL;
184 char *th_crit=NULL;
185 char type[8] = "";
186 output chld_out, chld_err;
187 char *previous_string=NULL;
188 char *ap=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;
193 time_t current_time;
194 double temp_double;
195 time_t duration;
196 char *conv = "12345678";
197 int is_counter=0;
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");
209 units = strdup ("");
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"));
227 if(calculate_rate) {
228 if (!strcmp(label, "SNMP"))
229 label = strdup("SNMP RATE");
230 time(&current_time);
231 i=0;
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) {
237 if(verbose>2)
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);
258 if (w) {
259 th_warn=strchr(th_warn, ',');
260 if (th_warn) th_warn++;
261 free(w);
263 if (c) {
264 th_crit=strchr(th_crit, ',');
265 if (th_crit) th_crit++;
266 free(c);
270 /* Create the command array to execute */
271 if(usesnmpgetnext == TRUE) {
272 snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
273 }else{
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;
307 if (verbose)
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)
318 external_error=1;
319 if (chld_out.lines == 0)
320 external_error=1;
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]);
327 } else {
328 printf(_("External command error with no output (return code: %d)\n"), return_code);
330 exit (STATE_UNKNOWN);
333 if (verbose) {
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++) {
340 if(calculate_rate)
341 conv = "%.10g";
342 else
343 conv = "%.0f";
345 ptr = chld_out.line[line];
346 oidname = strpcpy (oidname, ptr, delimiter);
347 response = strstr (ptr, delimiter);
348 if (response == NULL)
349 break;
351 if (verbose > 2) {
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));
358 is_counter=0;
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;
368 is_counter=1;
369 if(!calculate_rate)
370 strcpy(type, "c");
372 else if (strstr (response, "Counter64: ")) {
373 show = strstr (response, "Counter64: ") + 11;
374 is_counter=1;
375 if(!calculate_rate)
376 strcpy(type, "c");
378 else if (strstr (response, "INTEGER: ")) {
379 show = strstr (response, "INTEGER: ") + 9;
381 else if (strstr (response, "STRING: ")) {
382 show = strstr (response, "STRING: ") + 8;
383 conv = "%.10g";
385 /* Get the rest of the string on multi-line strings */
386 ptr = show;
387 COUNT_SEQ(ptr, bk_count, dq_count)
388 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
389 ptr++;
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') {
408 ptr++;
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: ");
421 else
422 show = response + 3;
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");
430 if (ptr == NULL)
431 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show);
432 response_value[i] = strtod (ptr, NULL);
434 if(calculate_rate) {
435 if (previous_state!=NULL) {
436 duration = current_time-previous_state->time;
437 if(duration<=0)
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) */
441 if(is_counter) {
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);
452 } else {
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;
462 else
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);
469 if (excode == 0) {
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);
477 else {
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? */
484 else {
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)
490 iresult = STATE_OK;
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));
501 else
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 */
510 ptr = NULL;
511 strtod(show, &ptr);
512 if (ptr > show) {
513 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
514 temp_string=labels[i];
515 else
516 temp_string=oidname;
517 if (strpbrk (temp_string, " ='\"") == NULL) {
518 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
519 } else {
520 if (strpbrk (temp_string, "'") == NULL) {
521 quote_string="'";
522 } else {
523 quote_string="\"";
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);
533 if (type)
534 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
535 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
538 total_oids=i;
540 /* Save state data, as all data collected now */
541 if(calculate_rate) {
542 string_length=1024;
543 state_string=malloc(string_length);
544 if(state_string==NULL)
545 die(STATE_UNKNOWN, _("Cannot malloc"));
547 current_length=0;
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]=':';
562 current_length++;
563 free(temp_string);
565 state_string[--current_length]='\0';
566 if (verbose > 2)
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);
580 return result;
585 /* process command-line arguments */
587 process_arguments (int argc, char **argv)
589 char *ptr;
590 int c = 1;
591 int j = 0, jj = 0, ii = 0;
593 int option = 0;
594 static struct option longopts[] = {
595 STD_LONG_OPTS,
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'},
623 {0, 0, 0, 0}
626 if (argc < 2)
627 return ERROR;
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");
639 while (1) {
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:",
641 longopts, &option);
643 if (c == -1 || c == EOF)
644 break;
646 switch (c) {
647 case '?': /* usage */
648 usage5 ();
649 case 'h': /* help */
650 print_help ();
651 exit (STATE_OK);
652 case 'V': /* version */
653 print_revision (progname, NP_VERSION);
654 exit (STATE_OK);
655 case 'v': /* verbose */
656 verbose++;
657 break;
659 /* Connection info */
660 case 'C': /* group or community */
661 community = optarg;
662 break;
663 case 'H': /* Host or server */
664 server_address = optarg;
665 break;
666 case 'p': /* TCP port number */
667 port = optarg;
668 break;
669 case 'm': /* List of MIBS */
670 miblist = optarg;
671 break;
672 case 'n': /* usesnmpgetnext */
673 usesnmpgetnext = TRUE;
674 break;
675 case 'P': /* SNMP protocol version */
676 proto = optarg;
677 break;
678 case 'L': /* security level */
679 seclevel = optarg;
680 break;
681 case 'U': /* security username */
682 secname = optarg;
683 break;
684 case 'a': /* auth protocol */
685 authproto = optarg;
686 break;
687 case 'x': /* priv protocol */
688 privproto = optarg;
689 break;
690 case 'A': /* auth passwd */
691 authpasswd = optarg;
692 break;
693 case 'X': /* priv passwd */
694 privpasswd = optarg;
695 break;
696 case 't': /* timeout period */
697 if (!is_integer (optarg))
698 usage2 (_("Timeout interval must be a positive integer"), optarg);
699 else
700 timeout_interval = atoi (optarg);
701 break;
703 /* Test parameters */
704 case 'c': /* critical threshold */
705 critical_thresholds = optarg;
706 break;
707 case 'w': /* warning threshold */
708 warning_thresholds = optarg;
709 break;
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);
714 else
715 retries = atoi(optarg);
716 break;
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
724 needmibs = TRUE;
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);
730 numoids = j;
731 if (c == 'E' || c == 'e') {
732 jj++;
733 ii++;
735 if (c == 'E')
736 eval_method[j+1] |= WARN_PRESENT;
737 else if (c == 'e')
738 eval_method[j+1] |= CRIT_PRESENT;
739 break;
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;
744 ii++;
745 break;
746 case 'R': /* regex */
747 cflags = REG_ICASE;
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);
753 if (errcode != 0) {
754 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
755 printf (_("Could Not Compile Regular Expression"));
756 return ERROR;
758 eval_method[jj++] = CRIT_REGEX;
759 ii++;
760 break;
762 /* Format */
763 case 'd': /* delimiter */
764 delimiter = strscpy (delimiter, optarg);
765 break;
766 case 'D': /* output-delimiter */
767 output_delim = strscpy (output_delim, optarg);
768 break;
769 case 'l': /* label */
770 nlabels++;
771 if (nlabels > labels_size) {
772 labels_size += 8;
773 labels = realloc (labels, labels_size * sizeof(*labels));
774 if (labels == NULL)
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;
780 if (ptr[0] == '\'')
781 labels[nlabels - 1] = ptr + 1;
782 while (ptr && (ptr = nextarg (ptr))) {
783 nlabels++;
784 if (nlabels > labels_size) {
785 labels_size += 8;
786 labels = realloc (labels, labels_size * sizeof(*labels));
787 if (labels == NULL)
788 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
790 ptr = thisarg (ptr);
791 if (ptr[0] == '\'')
792 labels[nlabels - 1] = ptr + 1;
793 else
794 labels[nlabels - 1] = ptr;
796 break;
797 case 'u': /* units */
798 units = optarg;
799 nunits++;
800 if (nunits > unitv_size) {
801 unitv_size += 8;
802 unitv = realloc (unitv, unitv_size * sizeof(*unitv));
803 if (unitv == NULL)
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;
809 if (ptr[0] == '\'')
810 unitv[nunits - 1] = ptr + 1;
811 while (ptr && (ptr = nextarg (ptr))) {
812 if (nunits > unitv_size) {
813 unitv_size += 8;
814 unitv = realloc (unitv, unitv_size * sizeof(*unitv));
815 if (units == NULL)
816 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
818 nunits++;
819 ptr = thisarg (ptr);
820 if (ptr[0] == '\'')
821 unitv[nunits - 1] = ptr + 1;
822 else
823 unitv[nunits - 1] = ptr;
825 break;
826 case L_CALCULATE_RATE:
827 if(calculate_rate==0)
828 np_enable_state(NULL, 1);
829 calculate_rate = 1;
830 break;
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);
834 break;
835 case L_INVERT_SEARCH:
836 invert_search=1;
837 break;
838 case 'O':
839 perf_labels=0;
840 break;
844 if (server_address == NULL)
845 server_address = argv[optind];
847 if (community == NULL)
848 community = strdup (DEFAULT_COMMUNITY);
850 return validate_arguments ();
854 /******************************************************************************
857 <sect3>
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
864 selected.</para>
866 <para></para>
868 </sect3>
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);
881 }else{
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 */
891 if (numoids == 0)
892 die(STATE_UNKNOWN, _("No OIDs specified\n"));
894 if (proto == NULL)
895 xasprintf(&proto, DEFAULT_PROTOCOL);
897 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
898 numauthpriv = 2;
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) {
908 numauthpriv = 2;
909 authpriv = calloc (numauthpriv, sizeof (char *));
910 authpriv[0] = strdup ("-l");
911 authpriv[1] = strdup ("noAuthNoPriv");
912 } else {
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);
920 if (secname == NULL)
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 ) {
927 numauthpriv = 8;
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");
944 numauthpriv = 12;
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);
962 else {
963 usage2 (_("Invalid SNMP version"), proto);
966 return OK;
971 /* trim leading whitespace
972 if there is a leading quote, make sure it balances */
974 char *
975 thisarg (char *str)
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"));
982 return str;
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 */
991 char *
992 nextarg (char *str)
994 if (str[0] == '\'') {
995 str[0] = 0;
996 if (strlen (str) > 1) {
997 str = strstr (str + 1, "'");
998 return (++str);
1000 else {
1001 return NULL;
1004 if (str[0] == ',') {
1005 str[0] = 0;
1006 if (strlen (str) > 1) {
1007 return (++str);
1009 else {
1010 return NULL;
1013 if ((str = strstr (str, ",")) && strlen (str) > 1) {
1014 str[0] = 0;
1015 return (++str);
1017 return NULL;
1022 void
1023 print_help (void)
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"));
1031 printf ("\n\n");
1033 print_usage ();
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"));
1063 /* OID Stuff */
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);
1111 printf ("\n");
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."));
1116 printf ("\n");
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."));
1128 printf("\n");
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);
1143 void
1144 print_usage (void)
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");