Merge pull request #2045 from RincewindsHat/fix/calloc_argument_order
[monitoring-plugins.git] / plugins / check_snmp.c
blobc1d8e2dd6b9cfb2edf4ada4d7d2405998e9381cf
1 /*****************************************************************************
3 * Monitoring check_snmp plugin
5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
8 * Description:
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-2024";
33 const char *email = "devel@monitoring-plugins.org";
35 #include "common.h"
36 #include "runcmd.h"
37 #include "utils.h"
38 #include "utils_cmd.h"
40 #define DEFAULT_COMMUNITY "public"
41 #define DEFAULT_PORT "161"
42 #define DEFAULT_MIBLIST "ALL"
43 #define DEFAULT_PROTOCOL "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 " "
49 #define DEFAULT_BUFFER_SIZE 100
51 #define mark(a) ((a) != 0 ? "*" : "")
53 #define CHECK_UNDEF 0
54 #define CRIT_PRESENT 1
55 #define CRIT_STRING 2
56 #define CRIT_REGEX 4
57 #define WARN_PRESENT 8
59 #define OID_COUNT_STEP 8
61 /* Longopts only arguments */
62 #define L_CALCULATE_RATE CHAR_MAX + 1
63 #define L_RATE_MULTIPLIER CHAR_MAX + 2
64 #define L_INVERT_SEARCH CHAR_MAX + 3
65 #define L_OFFSET CHAR_MAX + 4
66 #define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX + 5
68 /* Gobble to string - stop incrementing c when c[0] match one of the
69 * characters in s */
70 #define GOBBLE_TOS(c, s) \
71 while (c[0] != '\0' && strchr(s, c[0]) == NULL) { \
72 c++; \
74 /* Given c, keep track of backslashes (bk) and double-quotes (dq)
75 * from c[0] */
76 #define COUNT_SEQ(c, bk, dq) \
77 switch (c[0]) { \
78 case '\\': \
79 if (bk) \
80 bk--; \
81 else \
82 bk++; \
83 break; \
84 case '"': \
85 if (!dq) { \
86 dq++; \
87 } else if (!bk) { \
88 dq--; \
89 } else { \
90 bk--; \
91 } \
92 break; \
95 static int process_arguments(int, char **);
96 static int validate_arguments(void);
97 static char *thisarg(char *str);
98 static char *nextarg(char *str);
99 void print_usage(void);
100 static void print_help(void);
101 static char *multiply(char *str);
103 #include "regex.h"
104 static char regex_expect[MAX_INPUT_BUFFER] = "";
105 static regex_t preg;
106 static regmatch_t pmatch[10];
107 static char errbuf[MAX_INPUT_BUFFER] = "";
108 static char perfstr[MAX_INPUT_BUFFER] = "| ";
109 static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
110 static int eflags = 0;
111 static int errcode, excode;
113 static char *server_address = NULL;
114 static char *community = NULL;
115 static char **contextargs = NULL;
116 static char *context = NULL;
117 static char **authpriv = NULL;
118 static char *proto = NULL;
119 static char *seclevel = NULL;
120 static char *secname = NULL;
121 static char *authproto = NULL;
122 static char *privproto = NULL;
123 static char *authpasswd = NULL;
124 static char *privpasswd = NULL;
125 static int nulloid = STATE_UNKNOWN;
126 static char **oids = NULL;
127 static size_t oids_size = 0;
128 static char *label;
129 static char *units;
130 static char *port;
131 static char *snmpcmd;
132 static char string_value[MAX_INPUT_BUFFER] = "";
133 static int invert_search = 0;
134 static char **labels = NULL;
135 static char **unitv = NULL;
136 static size_t nlabels = 0;
137 static size_t labels_size = OID_COUNT_STEP;
138 static size_t nunits = 0;
139 static size_t unitv_size = OID_COUNT_STEP;
140 static size_t numoids = 0;
141 static int numauthpriv = 0;
142 static int numcontext = 0;
143 static int verbose = 0;
144 static bool usesnmpgetnext = false;
145 static char *warning_thresholds = NULL;
146 static char *critical_thresholds = NULL;
147 static thresholds **thlds;
148 static size_t thlds_size = OID_COUNT_STEP;
149 static double *response_value;
150 static size_t response_size = OID_COUNT_STEP;
151 static int retries = 0;
152 static int *eval_method;
153 static size_t eval_size = OID_COUNT_STEP;
154 static char *delimiter;
155 static char *output_delim;
156 static char *miblist = NULL;
157 static bool needmibs = false;
158 static int calculate_rate = 0;
159 static double offset = 0.0;
160 static int rate_multiplier = 1;
161 static state_data *previous_state;
162 static double *previous_value;
163 static size_t previous_size = OID_COUNT_STEP;
164 static int perf_labels = 1;
165 static char *ip_version = "";
166 static double multiplier = 1.0;
167 static char *fmtstr = "";
168 static bool fmtstr_set = false;
169 static char buffer[DEFAULT_BUFFER_SIZE];
170 static bool ignore_mib_parsing_errors = false;
172 static char *fix_snmp_range(char *th) {
173 double left;
174 double right;
175 char *colon;
176 char *ret;
178 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
179 return th;
181 left = strtod(th, NULL);
182 right = strtod(colon + 1, NULL);
183 if (right >= left)
184 return th;
186 if ((ret = malloc(strlen(th) + 2)) == NULL)
187 die(STATE_UNKNOWN, _("Cannot malloc"));
188 *colon = '\0';
189 sprintf(ret, "@%s:%s", colon + 1, th);
190 free(th);
191 return ret;
194 int main(int argc, char **argv) {
195 int len;
196 int total_oids;
197 size_t line;
198 unsigned int bk_count = 0;
199 unsigned int dq_count = 0;
200 int iresult = STATE_UNKNOWN;
201 int result = STATE_UNKNOWN;
202 int return_code = 0;
203 int external_error = 0;
204 char **command_line = NULL;
205 char *cl_hidden_auth = NULL;
206 char *oidname = NULL;
207 char *response = NULL;
208 char *mult_resp = NULL;
209 char *outbuff;
210 char *ptr = NULL;
211 char *show = NULL;
212 char *th_warn = NULL;
213 char *th_crit = NULL;
214 char type[8] = "";
215 output chld_out;
216 output chld_err;
217 char *previous_string = NULL;
218 char *ap = NULL;
219 char *state_string = NULL;
220 size_t response_length;
221 size_t current_length;
222 size_t string_length;
223 char *temp_string = NULL;
224 char *quote_string = NULL;
225 time_t current_time;
226 double temp_double;
227 time_t duration;
228 char *conv = "12345678";
229 int is_counter = 0;
231 setlocale(LC_ALL, "");
232 bindtextdomain(PACKAGE, LOCALEDIR);
233 textdomain(PACKAGE);
235 labels = malloc(labels_size * sizeof(*labels));
236 unitv = malloc(unitv_size * sizeof(*unitv));
237 thlds = malloc(thlds_size * sizeof(*thlds));
238 response_value = malloc(response_size * sizeof(*response_value));
239 previous_value = malloc(previous_size * sizeof(*previous_value));
240 eval_method = calloc(eval_size, sizeof(*eval_method));
241 oids = calloc(oids_size, sizeof(char *));
243 label = strdup("SNMP");
244 units = strdup("");
245 port = strdup(DEFAULT_PORT);
246 outbuff = strdup("");
247 delimiter = strdup(" = ");
248 output_delim = strdup(DEFAULT_OUTPUT_DELIMITER);
249 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
250 retries = DEFAULT_RETRIES;
252 np_init((char *)progname, argc, argv);
254 /* Parse extra opts if any */
255 argv = np_extra_opts(&argc, argv, progname);
257 np_set_args(argc, argv);
259 time(&current_time);
261 if (process_arguments(argc, argv) == ERROR)
262 usage4(_("Could not parse arguments"));
264 if (calculate_rate) {
265 if (!strcmp(label, "SNMP"))
266 label = strdup("SNMP RATE");
268 size_t i = 0;
270 previous_state = np_state_read();
271 if (previous_state != NULL) {
272 /* Split colon separated values */
273 previous_string = strdup((char *)previous_state->data);
274 while ((ap = strsep(&previous_string, ":")) != NULL) {
275 if (verbose > 2)
276 printf("State for %zd=%s\n", i, ap);
277 while (i >= previous_size) {
278 previous_size += OID_COUNT_STEP;
279 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
281 previous_value[i++] = strtod(ap, NULL);
286 /* Populate the thresholds */
287 th_warn = warning_thresholds;
288 th_crit = critical_thresholds;
289 for (size_t i = 0; i < numoids; i++) {
290 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
291 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
292 /* translate "2:1" to "@1:2" for backwards compatibility */
293 w = w ? fix_snmp_range(w) : NULL;
294 c = c ? fix_snmp_range(c) : NULL;
296 while (i >= thlds_size) {
297 thlds_size += OID_COUNT_STEP;
298 thlds = realloc(thlds, thlds_size * sizeof(*thlds));
301 /* Skip empty thresholds, while avoiding segfault */
302 set_thresholds(&thlds[i], w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
303 if (w) {
304 th_warn = strchr(th_warn, ',');
305 if (th_warn)
306 th_warn++;
307 free(w);
309 if (c) {
310 th_crit = strchr(th_crit, ',');
311 if (th_crit)
312 th_crit++;
313 free(c);
317 /* Create the command array to execute */
318 if (usesnmpgetnext) {
319 snmpcmd = strdup(PATH_TO_SNMPGETNEXT);
320 } else {
321 snmpcmd = strdup(PATH_TO_SNMPGET);
324 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */
326 unsigned index = 0;
327 command_line = calloc(11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof(char *));
329 command_line[index++] = snmpcmd;
330 command_line[index++] = strdup("-Le");
331 command_line[index++] = strdup("-t");
332 xasprintf(&command_line[index++], "%d", timeout_interval);
333 command_line[index++] = strdup("-r");
334 xasprintf(&command_line[index++], "%d", retries);
335 command_line[index++] = strdup("-m");
336 command_line[index++] = strdup(miblist);
337 command_line[index++] = "-v";
338 command_line[index++] = strdup(proto);
340 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''",
341 proto);
343 if (ignore_mib_parsing_errors) {
344 command_line[index++] = "-Pe";
345 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth);
348 for (int i = 0; i < numcontext; i++) {
349 command_line[index++] = contextargs[i];
352 for (int i = 0; i < numauthpriv; i++) {
353 command_line[index++] = authpriv[i];
356 xasprintf(&command_line[index++], "%s:%s", server_address, port);
358 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", cl_hidden_auth, server_address, port);
360 for (size_t i = 0; i < numoids; i++) {
361 command_line[index++] = oids[i];
362 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
365 command_line[index++] = NULL;
367 if (verbose) {
368 printf("%s\n", cl_hidden_auth);
371 /* Set signal handling and alarm */
372 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
373 usage4(_("Cannot catch SIGALRM"));
375 alarm(timeout_interval * retries + 5);
377 /* Run the command */
378 return_code = cmd_run_array(command_line, &chld_out, &chld_err, 0);
380 /* disable alarm again */
381 alarm(0);
383 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
384 only return state unknown if return code is non zero or there is no stdout.
385 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
387 if (return_code != 0)
388 external_error = 1;
389 if (chld_out.lines == 0)
390 external_error = 1;
391 if (external_error) {
392 if (chld_err.lines > 0) {
393 printf(_("External command error: %s\n"), chld_err.line[0]);
394 for (size_t i = 1; i < chld_err.lines; i++) {
395 printf("%s\n", chld_err.line[i]);
397 } else {
398 printf(_("External command error with no output (return code: %d)\n"), return_code);
400 exit(STATE_UNKNOWN);
403 if (verbose) {
404 for (size_t i = 0; i < chld_out.lines; i++) {
405 printf("%s\n", chld_out.line[i]);
409 line = 0;
410 total_oids = 0;
411 for (size_t i = 0; line < chld_out.lines && i < numoids; line++, i++, total_oids++) {
412 if (calculate_rate)
413 conv = "%.10g";
414 else
415 conv = "%.0f";
417 ptr = chld_out.line[line];
418 oidname = strpcpy(oidname, ptr, delimiter);
419 response = strstr(ptr, delimiter);
420 if (response == NULL)
421 break;
423 if (verbose > 2) {
424 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i + 1, line + 1, oidname, response);
427 /* Clean up type array - Sol10 does not necessarily zero it out */
428 bzero(type, sizeof(type));
430 is_counter = 0;
431 /* We strip out the datatype indicator for PHBs */
432 if (strstr(response, "Gauge: ")) {
433 show = multiply(strstr(response, "Gauge: ") + 7);
434 } else if (strstr(response, "Gauge32: ")) {
435 show = multiply(strstr(response, "Gauge32: ") + 9);
436 } else if (strstr(response, "Counter32: ")) {
437 show = strstr(response, "Counter32: ") + 11;
438 is_counter = 1;
439 if (!calculate_rate)
440 strcpy(type, "c");
441 } else if (strstr(response, "Counter64: ")) {
442 show = strstr(response, "Counter64: ") + 11;
443 is_counter = 1;
444 if (!calculate_rate)
445 strcpy(type, "c");
446 } else if (strstr(response, "INTEGER: ")) {
447 show = multiply(strstr(response, "INTEGER: ") + 9);
449 if (fmtstr_set) {
450 conv = fmtstr;
452 } else if (strstr(response, "OID: ")) {
453 show = strstr(response, "OID: ") + 5;
454 } else if (strstr(response, "STRING: ")) {
455 show = strstr(response, "STRING: ") + 8;
456 conv = "%.10g";
458 /* Get the rest of the string on multi-line strings */
459 ptr = show;
460 COUNT_SEQ(ptr, bk_count, dq_count)
461 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
462 ptr++;
463 GOBBLE_TOS(ptr, "\n\"\\")
464 COUNT_SEQ(ptr, bk_count, dq_count)
467 if (dq_count) { /* unfinished line */
468 /* copy show verbatim first */
469 if (!mult_resp)
470 mult_resp = strdup("");
471 xasprintf(&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
472 /* then strip out unmatched double-quote from single-line output */
473 if (show[0] == '"')
474 show++;
476 /* Keep reading until we match end of double-quoted string */
477 for (line++; line < chld_out.lines; line++) {
478 ptr = chld_out.line[line];
479 xasprintf(&mult_resp, "%s%s\n", mult_resp, ptr);
481 COUNT_SEQ(ptr, bk_count, dq_count)
482 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
483 ptr++;
484 GOBBLE_TOS(ptr, "\n\"\\")
485 COUNT_SEQ(ptr, bk_count, dq_count)
487 /* Break for loop before next line increment when done */
488 if (!dq_count)
489 break;
493 } else if (strstr(response, "Timeticks: ")) {
494 show = strstr(response, "Timeticks: ");
495 } else
496 show = response + 3;
498 iresult = STATE_DEPENDENT;
500 /* Process this block for numeric comparisons */
501 /* Make some special values,like Timeticks numeric only if a threshold is defined */
502 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) {
503 if (verbose > 2) {
504 print_thresholds(" thresholds", thlds[i]);
506 ptr = strpbrk(show, "-0123456789");
507 if (ptr == NULL) {
508 if (nulloid == 3)
509 die(STATE_UNKNOWN, _("No valid data returned (%s)\n"), show);
510 else if (nulloid == 0)
511 die(STATE_OK, _("No valid data returned (%s)\n"), show);
512 else if (nulloid == 1)
513 die(STATE_WARNING, _("No valid data returned (%s)\n"), show);
514 else if (nulloid == 2)
515 die(STATE_CRITICAL, _("No valid data returned (%s)\n"), show);
517 while (i >= response_size) {
518 response_size += OID_COUNT_STEP;
519 response_value = realloc(response_value, response_size * sizeof(*response_value));
521 response_value[i] = strtod(ptr, NULL) + offset;
523 if (calculate_rate) {
524 if (previous_state != NULL) {
525 duration = current_time - previous_state->time;
526 if (duration <= 0)
527 die(STATE_UNKNOWN, _("Time duration between plugin calls is invalid"));
528 temp_double = response_value[i] - previous_value[i];
529 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
530 if (is_counter) {
531 if (temp_double < (double)0.0)
532 temp_double += (double)4294967296.0; /* 2^32 */
533 if (temp_double < (double)0.0)
534 temp_double += (double)18446744069414584320.0; /* 2^64-2^32 */
537 /* Convert to per second, then use multiplier */
538 temp_double = temp_double / duration * rate_multiplier;
539 iresult = get_status(temp_double, thlds[i]);
540 xasprintf(&show, conv, temp_double);
542 } else {
543 iresult = get_status(response_value[i], thlds[i]);
544 xasprintf(&show, conv, response_value[i]);
548 /* Process this block for string matching */
549 else if (eval_size > i && eval_method[i] & CRIT_STRING) {
550 if (strcmp(show, string_value))
551 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
552 else
553 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
556 /* Process this block for regex matching */
557 else if (eval_size > i && eval_method[i] & CRIT_REGEX) {
558 excode = regexec(&preg, response, 10, pmatch, eflags);
559 if (excode == 0) {
560 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
561 } else if (excode != REG_NOMATCH) {
562 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
563 printf(_("Execute Error: %s\n"), errbuf);
564 exit(STATE_CRITICAL);
565 } else {
566 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
570 /* Process this block for existence-nonexistence checks */
571 /* TV: Should this be outside of this else block? */
572 else {
573 if (eval_size > i && eval_method[i] & CRIT_PRESENT)
574 iresult = STATE_CRITICAL;
575 else if (eval_size > i && eval_method[i] & WARN_PRESENT)
576 iresult = STATE_WARNING;
577 else if (response && iresult == STATE_DEPENDENT)
578 iresult = STATE_OK;
581 /* Result is the worst outcome of all the OIDs tested */
582 result = max_state(result, iresult);
584 /* Prepend a label for this OID if there is one */
585 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
586 xasprintf(&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark(iresult), show, mark(iresult));
587 else
588 xasprintf(&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, mark(iresult), show, mark(iresult));
590 /* Append a unit string for this OID if there is one */
591 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
592 xasprintf(&outbuff, "%s %s", outbuff, unitv[i]);
594 /* Write perfdata with whatever can be parsed by strtod, if possible */
595 ptr = NULL;
596 strtod(show, &ptr);
597 if (ptr > show) {
598 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
599 temp_string = labels[i];
600 else
601 temp_string = oidname;
602 if (strpbrk(temp_string, " ='\"") == NULL) {
603 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1);
604 } else {
605 if (strpbrk(temp_string, "'") == NULL) {
606 quote_string = "'";
607 } else {
608 quote_string = "\"";
610 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1);
611 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1);
612 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1);
614 strncat(perfstr, "=", sizeof(perfstr) - strlen(perfstr) - 1);
615 len = sizeof(perfstr) - strlen(perfstr) - 1;
616 strncat(perfstr, show, len > ptr - show ? ptr - show : len);
618 if (strcmp(type, "") != 0) {
619 strncat(perfstr, type, sizeof(perfstr) - strlen(perfstr) - 1);
622 if (warning_thresholds) {
623 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
624 if (thlds[i]->warning && thlds[i]->warning->text)
625 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr) - strlen(perfstr) - 1);
628 if (critical_thresholds) {
629 if (!warning_thresholds)
630 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
631 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
632 if (thlds[i]->critical && thlds[i]->critical->text)
633 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr) - strlen(perfstr) - 1);
636 strncat(perfstr, " ", sizeof(perfstr) - strlen(perfstr) - 1);
640 /* Save state data, as all data collected now */
641 if (calculate_rate) {
642 string_length = 1024;
643 state_string = malloc(string_length);
644 if (state_string == NULL)
645 die(STATE_UNKNOWN, _("Cannot malloc"));
647 current_length = 0;
648 for (int i = 0; i < total_oids; i++) {
649 xasprintf(&temp_string, "%.0f", response_value[i]);
650 if (temp_string == NULL)
651 die(STATE_UNKNOWN, _("Cannot asprintf()"));
652 response_length = strlen(temp_string);
653 if (current_length + response_length > string_length) {
654 string_length = current_length + 1024;
655 state_string = realloc(state_string, string_length);
656 if (state_string == NULL)
657 die(STATE_UNKNOWN, _("Cannot realloc()"));
659 strcpy(&state_string[current_length], temp_string);
660 current_length = current_length + response_length;
661 state_string[current_length] = ':';
662 current_length++;
663 free(temp_string);
665 state_string[--current_length] = '\0';
666 if (verbose > 2)
667 printf("State string=%s\n", state_string);
669 /* This is not strictly the same as time now, but any subtle variations will cancel out */
670 np_state_write_string(current_time, state_string);
671 if (previous_state == NULL) {
672 /* Or should this be highest state? */
673 die(STATE_OK, _("No previous data to calculate rate - assume okay"));
677 printf("%s %s -%s %s\n", label, state_text(result), outbuff, perfstr);
678 if (mult_resp)
679 printf("%s", mult_resp);
681 return result;
684 /* process command-line arguments */
685 int process_arguments(int argc, char **argv) {
686 static struct option longopts[] = {STD_LONG_OPTS,
687 {"community", required_argument, 0, 'C'},
688 {"oid", required_argument, 0, 'o'},
689 {"object", required_argument, 0, 'o'},
690 {"delimiter", required_argument, 0, 'd'},
691 {"nulloid", required_argument, 0, 'z'},
692 {"output-delimiter", required_argument, 0, 'D'},
693 {"string", required_argument, 0, 's'},
694 {"timeout", required_argument, 0, 't'},
695 {"regex", required_argument, 0, 'r'},
696 {"ereg", required_argument, 0, 'r'},
697 {"eregi", required_argument, 0, 'R'},
698 {"label", required_argument, 0, 'l'},
699 {"units", required_argument, 0, 'u'},
700 {"port", required_argument, 0, 'p'},
701 {"retries", required_argument, 0, 'e'},
702 {"miblist", required_argument, 0, 'm'},
703 {"protocol", required_argument, 0, 'P'},
704 {"context", required_argument, 0, 'N'},
705 {"seclevel", required_argument, 0, 'L'},
706 {"secname", required_argument, 0, 'U'},
707 {"authproto", required_argument, 0, 'a'},
708 {"privproto", required_argument, 0, 'x'},
709 {"authpasswd", required_argument, 0, 'A'},
710 {"privpasswd", required_argument, 0, 'X'},
711 {"next", no_argument, 0, 'n'},
712 {"rate", no_argument, 0, L_CALCULATE_RATE},
713 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
714 {"offset", required_argument, 0, L_OFFSET},
715 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
716 {"perf-oids", no_argument, 0, 'O'},
717 {"ipv4", no_argument, 0, '4'},
718 {"ipv6", no_argument, 0, '6'},
719 {"multiplier", required_argument, 0, 'M'},
720 {"fmtstr", required_argument, 0, 'f'},
721 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
722 {0, 0, 0, 0}};
724 if (argc < 2)
725 return ERROR;
727 /* reverse compatibility for very old non-POSIX usage forms */
728 for (int c = 1; c < argc; c++) {
729 if (strcmp("-to", argv[c]) == 0)
730 strcpy(argv[c], "-t");
731 if (strcmp("-wv", argv[c]) == 0)
732 strcpy(argv[c], "-w");
733 if (strcmp("-cv", argv[c]) == 0)
734 strcpy(argv[c], "-c");
737 size_t j = 0;
738 size_t jj = 0;
739 while (true) {
740 int option = 0;
741 int option_char = getopt_long(argc, argv, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option);
743 if (option_char == -1 || option_char == EOF)
744 break;
746 switch (option_char) {
747 case '?': /* usage */
748 usage5();
749 case 'h': /* help */
750 print_help();
751 exit(STATE_UNKNOWN);
752 case 'V': /* version */
753 print_revision(progname, NP_VERSION);
754 exit(STATE_UNKNOWN);
755 case 'v': /* verbose */
756 verbose++;
757 break;
759 /* Connection info */
760 case 'C': /* group or community */
761 community = optarg;
762 break;
763 case 'H': /* Host or server */
764 server_address = optarg;
765 break;
766 case 'p': /* TCP port number */
767 port = optarg;
768 break;
769 case 'm': /* List of MIBS */
770 miblist = optarg;
771 break;
772 case 'n': /* usesnmpgetnext */
773 usesnmpgetnext = true;
774 break;
775 case 'P': /* SNMP protocol version */
776 proto = optarg;
777 break;
778 case 'N': /* SNMPv3 context */
779 context = optarg;
780 break;
781 case 'L': /* security level */
782 seclevel = optarg;
783 break;
784 case 'U': /* security username */
785 secname = optarg;
786 break;
787 case 'a': /* auth protocol */
788 authproto = optarg;
789 break;
790 case 'x': /* priv protocol */
791 privproto = optarg;
792 break;
793 case 'A': /* auth passwd */
794 authpasswd = optarg;
795 break;
796 case 'X': /* priv passwd */
797 privpasswd = optarg;
798 break;
799 case 't': /* timeout period */
800 if (!is_integer(optarg))
801 usage2(_("Timeout interval must be a positive integer"), optarg);
802 else
803 timeout_interval = atoi(optarg);
804 break;
806 /* Test parameters */
807 case 'c': /* critical threshold */
808 critical_thresholds = optarg;
809 break;
810 case 'w': /* warning threshold */
811 warning_thresholds = optarg;
812 break;
813 case 'e': /* PRELIMINARY - may change */
814 case 'E': /* PRELIMINARY - may change */
815 if (!is_integer(optarg))
816 usage2(_("Retries interval must be a positive integer"), optarg);
817 else
818 retries = atoi(optarg);
819 break;
820 case 'o': /* object identifier */
821 if (strspn(optarg, "0123456789.,") != strlen(optarg)) {
823 * we have something other than digits, periods and comas,
824 * so we have a mib variable, rather than just an SNMP OID,
825 * so we have to actually read the mib files
827 needmibs = true;
829 for (char *ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) {
830 while (j >= oids_size) {
831 oids_size += OID_COUNT_STEP;
832 oids = realloc(oids, oids_size * sizeof(*oids));
834 oids[j] = strdup(ptr);
836 numoids = j;
837 if (option_char == 'E' || option_char == 'e') {
838 jj++;
839 while (j + 1 >= eval_size) {
840 eval_size += OID_COUNT_STEP;
841 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
842 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
844 if (option_char == 'E')
845 eval_method[j + 1] |= WARN_PRESENT;
846 else if (option_char == 'e')
847 eval_method[j + 1] |= CRIT_PRESENT;
849 break;
850 case 'z': /* Null OID Return Check */
851 if (!is_integer(optarg))
852 usage2(_("Exit status must be a positive integer"), optarg);
853 else
854 nulloid = atoi(optarg);
855 break;
856 case 's': /* string or substring */
857 strncpy(string_value, optarg, sizeof(string_value) - 1);
858 string_value[sizeof(string_value) - 1] = 0;
859 while (jj >= eval_size) {
860 eval_size += OID_COUNT_STEP;
861 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
862 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
864 eval_method[jj++] = CRIT_STRING;
865 break;
866 case 'R': /* regex */
867 cflags = REG_ICASE;
868 // fall through
869 case 'r': /* regex */
870 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
871 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1);
872 regex_expect[sizeof(regex_expect) - 1] = 0;
873 errcode = regcomp(&preg, regex_expect, cflags);
874 if (errcode != 0) {
875 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
876 printf(_("Could Not Compile Regular Expression"));
877 return ERROR;
879 while (jj >= eval_size) {
880 eval_size += OID_COUNT_STEP;
881 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
882 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
884 eval_method[jj++] = CRIT_REGEX;
885 break;
887 /* Format */
888 case 'd': /* delimiter */
889 delimiter = strscpy(delimiter, optarg);
890 break;
891 case 'D': /* output-delimiter */
892 output_delim = strscpy(output_delim, optarg);
893 break;
894 case 'l': /* label */
895 nlabels++;
896 if (nlabels > labels_size) {
897 labels_size += 8;
898 labels = realloc(labels, labels_size * sizeof(*labels));
899 if (labels == NULL)
900 die(STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
902 labels[nlabels - 1] = optarg;
903 char *ptr = thisarg(optarg);
904 labels[nlabels - 1] = ptr;
905 if (ptr[0] == '\'')
906 labels[nlabels - 1] = ptr + 1;
907 while (ptr && (ptr = nextarg(ptr))) {
908 nlabels++;
909 if (nlabels > labels_size) {
910 labels_size += 8;
911 labels = realloc(labels, labels_size * sizeof(*labels));
912 if (labels == NULL)
913 die(STATE_UNKNOWN, _("Could not reallocate labels\n"));
915 ptr = thisarg(ptr);
916 if (ptr[0] == '\'')
917 labels[nlabels - 1] = ptr + 1;
918 else
919 labels[nlabels - 1] = ptr;
921 break;
922 case 'u': /* units */
923 units = optarg;
924 nunits++;
925 if (nunits > unitv_size) {
926 unitv_size += 8;
927 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
928 if (unitv == NULL)
929 die(STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
931 unitv[nunits - 1] = optarg;
932 ptr = thisarg(optarg);
933 unitv[nunits - 1] = ptr;
934 if (ptr[0] == '\'')
935 unitv[nunits - 1] = ptr + 1;
936 while (ptr && (ptr = nextarg(ptr))) {
937 if (nunits > unitv_size) {
938 unitv_size += 8;
939 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
940 if (units == NULL)
941 die(STATE_UNKNOWN, _("Could not realloc() units\n"));
943 nunits++;
944 ptr = thisarg(ptr);
945 if (ptr[0] == '\'')
946 unitv[nunits - 1] = ptr + 1;
947 else
948 unitv[nunits - 1] = ptr;
950 break;
951 case L_CALCULATE_RATE:
952 if (calculate_rate == 0)
953 np_enable_state(NULL, 1);
954 calculate_rate = 1;
955 break;
956 case L_RATE_MULTIPLIER:
957 if (!is_integer(optarg) || ((rate_multiplier = atoi(optarg)) <= 0))
958 usage2(_("Rate multiplier must be a positive integer"), optarg);
959 break;
960 case L_OFFSET:
961 offset = strtod(optarg, NULL);
962 break;
963 case L_INVERT_SEARCH:
964 invert_search = 1;
965 break;
966 case 'O':
967 perf_labels = 0;
968 break;
969 case '4':
970 break;
971 case '6':
972 xasprintf(&ip_version, "udp6:");
973 if (verbose > 2)
974 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n");
975 break;
976 case 'M':
977 if (strspn(optarg, "0123456789.,") == strlen(optarg)) {
978 multiplier = strtod(optarg, NULL);
980 break;
981 case 'f':
982 if (multiplier != 1.0) {
983 fmtstr = optarg;
984 fmtstr_set = true;
986 break;
987 case L_IGNORE_MIB_PARSING_ERRORS:
988 ignore_mib_parsing_errors = true;
992 if (server_address == NULL)
993 server_address = argv[optind];
995 if (community == NULL)
996 community = strdup(DEFAULT_COMMUNITY);
998 return validate_arguments();
1001 /******************************************************************************
1004 <sect3>
1005 <title>validate_arguments</title>
1007 <para>&PROTO_validate_arguments;</para>
1009 <para>Checks to see if the default miblist needs to be loaded. Also verifies
1010 the authentication and authorization combinations based on protocol version
1011 selected.</para>
1013 <para></para>
1015 </sect3>
1017 ******************************************************************************/
1019 static int validate_arguments() {
1020 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1021 if (miblist == NULL) {
1022 if (needmibs) {
1023 miblist = strdup(DEFAULT_MIBLIST);
1024 } else {
1025 miblist = ""; /* don't read any mib files for numeric oids */
1029 /* Check server_address is given */
1030 if (server_address == NULL)
1031 die(STATE_UNKNOWN, _("No host specified\n"));
1033 /* Check oid is given */
1034 if (numoids == 0)
1035 die(STATE_UNKNOWN, _("No OIDs specified\n"));
1037 if (proto == NULL)
1038 xasprintf(&proto, DEFAULT_PROTOCOL);
1040 if ((strcmp(proto, "1") == 0) || (strcmp(proto, "2c") == 0)) { /* snmpv1 or snmpv2c */
1041 numauthpriv = 2;
1042 authpriv = calloc(numauthpriv, sizeof(char *));
1043 authpriv[0] = strdup("-c");
1044 authpriv[1] = strdup(community);
1045 } else if (strcmp(proto, "3") == 0) { /* snmpv3 args */
1046 if (!(context == NULL)) {
1047 numcontext = 2;
1048 contextargs = calloc(numcontext, sizeof(char *));
1049 contextargs[0] = strdup("-n");
1050 contextargs[1] = strdup(context);
1053 if (seclevel == NULL)
1054 xasprintf(&seclevel, "noAuthNoPriv");
1056 if (secname == NULL)
1057 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
1059 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
1060 numauthpriv = 4;
1061 authpriv = calloc(numauthpriv, sizeof(char *));
1062 authpriv[0] = strdup("-l");
1063 authpriv[1] = strdup("noAuthNoPriv");
1064 authpriv[2] = strdup("-u");
1065 authpriv[3] = strdup(secname);
1066 } else {
1067 if (!((strcmp(seclevel, "authNoPriv") == 0) || (strcmp(seclevel, "authPriv") == 0))) {
1068 usage2(_("Invalid seclevel"), seclevel);
1071 if (authproto == NULL)
1072 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
1074 if (authpasswd == NULL)
1075 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
1077 if (strcmp(seclevel, "authNoPriv") == 0) {
1078 numauthpriv = 8;
1079 authpriv = calloc(numauthpriv, sizeof(char *));
1080 authpriv[0] = strdup("-l");
1081 authpriv[1] = strdup("authNoPriv");
1082 authpriv[2] = strdup("-a");
1083 authpriv[3] = strdup(authproto);
1084 authpriv[4] = strdup("-u");
1085 authpriv[5] = strdup(secname);
1086 authpriv[6] = strdup("-A");
1087 authpriv[7] = strdup(authpasswd);
1088 } else if (strcmp(seclevel, "authPriv") == 0) {
1089 if (privproto == NULL)
1090 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
1092 if (privpasswd == NULL)
1093 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
1095 numauthpriv = 12;
1096 authpriv = calloc(numauthpriv, sizeof(char *));
1097 authpriv[0] = strdup("-l");
1098 authpriv[1] = strdup("authPriv");
1099 authpriv[2] = strdup("-a");
1100 authpriv[3] = strdup(authproto);
1101 authpriv[4] = strdup("-u");
1102 authpriv[5] = strdup(secname);
1103 authpriv[6] = strdup("-A");
1104 authpriv[7] = strdup(authpasswd);
1105 authpriv[8] = strdup("-x");
1106 authpriv[9] = strdup(privproto);
1107 authpriv[10] = strdup("-X");
1108 authpriv[11] = strdup(privpasswd);
1112 } else {
1113 usage2(_("Invalid SNMP version"), proto);
1116 return OK;
1119 /* trim leading whitespace
1120 if there is a leading quote, make sure it balances */
1122 static char *thisarg(char *str) {
1123 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
1124 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1125 if (strlen(str) == 1 || !strstr(str + 1, "'"))
1126 die(STATE_UNKNOWN, _("Unbalanced quotes\n"));
1128 return str;
1131 /* if there's a leading quote, advance to the trailing quote
1132 set the trailing quote to '\x0'
1133 if the string continues, advance beyond the comma */
1135 static char *nextarg(char *str) {
1136 if (str[0] == '\'') {
1137 str[0] = 0;
1138 if (strlen(str) > 1) {
1139 str = strstr(str + 1, "'");
1140 return (++str);
1141 } else {
1142 return NULL;
1145 if (str[0] == ',') {
1146 str[0] = 0;
1147 if (strlen(str) > 1) {
1148 return (++str);
1149 } else {
1150 return NULL;
1153 if ((str = strstr(str, ",")) && strlen(str) > 1) {
1154 str[0] = 0;
1155 return (++str);
1157 return NULL;
1160 /* multiply result (values 0 < n < 1 work as divider) */
1161 static char *multiply(char *str) {
1162 if (multiplier == 1)
1163 return (str);
1165 if (verbose > 2)
1166 printf(" multiply input: %s\n", str);
1168 char *endptr;
1169 double val = strtod(str, &endptr);
1170 if ((val == 0.0) && (endptr == str)) {
1171 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
1174 if (verbose > 2)
1175 printf(" multiply extracted double: %f\n", val);
1177 val *= multiplier;
1178 char *conv = "%f";
1179 if (fmtstr_set) {
1180 conv = fmtstr;
1182 if (val == (int)val) {
1183 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1184 } else {
1185 if (verbose > 2)
1186 printf(" multiply using format: %s\n", conv);
1187 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1189 if (verbose > 2)
1190 printf(" multiply result: %s\n", buffer);
1191 return buffer;
1194 static void print_help(void) {
1195 print_revision(progname, NP_VERSION);
1197 printf(COPYRIGHT, copyright, email);
1199 printf("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1201 printf("\n\n");
1203 print_usage();
1205 printf(UT_HELP_VRSN);
1206 printf(UT_EXTRA_OPTS);
1207 printf(UT_IPv46);
1209 printf(UT_HOST_PORT, 'p', DEFAULT_PORT);
1211 /* SNMP and Authentication Protocol */
1212 printf(" %s\n", "-n, --next");
1213 printf(" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1214 printf(" %s\n", "-P, --protocol=[1|2c|3]");
1215 printf(" %s\n", _("SNMP protocol version"));
1216 printf(" %s\n", "-N, --context=CONTEXT");
1217 printf(" %s\n", _("SNMPv3 context"));
1218 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1219 printf(" %s\n", _("SNMPv3 securityLevel"));
1220 printf(" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL");
1221 printf(" %s\n",
1222 _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools"));
1223 printf(" %s\n", _("if < 5.8 SHA (1) and MD5 should be available, if >= 5.8 additionally SHA-224, SHA-256, SHA-384 and SHA-512"));
1224 printf(" %s\n", "-x, --privproto=PRIVACY_PROTOCOL");
1225 printf(" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools"));
1226 printf(" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256"));
1228 /* Authentication Tokens*/
1229 printf(" %s\n", "-C, --community=STRING");
1230 printf(" %s ", _("Optional community string for SNMP communication"));
1231 printf("(%s \"%s\")\n", _("default is"), DEFAULT_COMMUNITY);
1232 printf(" %s\n", "-U, --secname=USERNAME");
1233 printf(" %s\n", _("SNMPv3 username"));
1234 printf(" %s\n", "-A, --authpasswd=PASSWORD");
1235 printf(" %s\n", _("SNMPv3 authentication password"));
1236 printf(" %s\n", "-X, --privpasswd=PASSWORD");
1237 printf(" %s\n", _("SNMPv3 privacy password"));
1239 /* OID Stuff */
1240 printf(" %s\n", "-o, --oid=OID(s)");
1241 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1242 printf(" %s\n", "-m, --miblist=STRING");
1243 printf(" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1244 printf(" %s\n", _("for symbolic OIDs.)"));
1245 printf(" %s\n", "-d, --delimiter=STRING");
1246 printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1247 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1248 printf(" %s\n", _("to be the data that should be used in the evaluation."));
1249 printf(" %s\n", "-z, --nulloid=#");
1250 printf(" %s\n", _("If the check returns a 0 length string or NULL value"));
1251 printf(" %s\n", _("This option allows you to choose what status you want it to exit"));
1252 printf(" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1253 printf(" %s\n", _("0 = OK"));
1254 printf(" %s\n", _("1 = WARNING"));
1255 printf(" %s\n", _("2 = CRITICAL"));
1256 printf(" %s\n", _("3 = UNKNOWN"));
1258 /* Tests Against Integers */
1259 printf(" %s\n", "-w, --warning=THRESHOLD(s)");
1260 printf(" %s\n", _("Warning threshold range(s)"));
1261 printf(" %s\n", "-c, --critical=THRESHOLD(s)");
1262 printf(" %s\n", _("Critical threshold range(s)"));
1263 printf(" %s\n", "--rate");
1264 printf(" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1265 printf(" %s\n", "--rate-multiplier");
1266 printf(" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1267 printf(" %s\n", "--offset=OFFSET");
1268 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1270 /* Tests Against Strings */
1271 printf(" %s\n", "-s, --string=STRING");
1272 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1273 printf(" %s\n", "-r, --ereg=REGEX");
1274 printf(" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1275 printf(" %s\n", "-R, --eregi=REGEX");
1276 printf(" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1277 printf(" %s\n", "--invert-search");
1278 printf(" %s\n", _("Invert search result (CRITICAL if found)"));
1280 /* Output Formatting */
1281 printf(" %s\n", "-l, --label=STRING");
1282 printf(" %s\n", _("Prefix label for output from plugin"));
1283 printf(" %s\n", "-u, --units=STRING");
1284 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1285 printf(" %s\n", "-D, --output-delimiter=STRING");
1286 printf(" %s\n", _("Separates output on multiple OID requests"));
1287 printf(" %s\n", "-M, --multiplier=FLOAT");
1288 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1289 printf(" %s\n", "-f, --fmtstr=STRING");
1290 printf(" %s\n", _("C-style format string for float values (see option -M)"));
1292 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1293 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
1294 printf(" %s\n", "-e, --retries=INTEGER");
1295 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES);
1297 printf(" %s\n", "-O, --perf-oids");
1298 printf(" %s\n", _("Label performance data with OIDs instead of --label's"));
1300 printf(" %s\n", "--ignore-mib-parsing-errors");
1301 printf(" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1303 printf(UT_VERBOSE);
1305 printf("\n");
1306 printf("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1307 printf("%s\n", _("if you don't have the package installed, you will need to download it from"));
1308 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1310 printf("\n");
1311 printf("%s\n", _("Notes:"));
1312 printf(" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1313 printf(" %s\n", _("list (lists with internal spaces must be quoted)."));
1315 printf(" -%s", UT_THRESHOLDS_NOTES);
1317 printf(" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1318 printf(" %s\n", _("- Note that only one string and one regex may be checked at present"));
1319 printf(" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1320 printf(" %s\n", _("returned from the SNMP query is an unsigned integer."));
1322 printf("\n");
1323 printf("%s\n", _("Rate Calculation:"));
1324 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1325 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1326 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1327 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1328 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1329 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1330 printf(" %s\n", _("changing the arguments will create a new state file."));
1332 printf(UT_SUPPORT);
1335 void print_usage(void) {
1336 printf("%s\n", _("Usage:"));
1337 printf("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n", progname);
1338 printf("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1339 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1340 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1341 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1342 printf("[-M multiplier [-f format]]\n");