1 /*
2 * snmptable.c - walk a table and print it nicely
3 *
4 * Update: 1999-10-26 <rs-snmp@revelstone.com>
5 * Added ability to use MIB to query tables with non-sequential column OIDs
6 * Added code to handle sparse tables
7 *
8 * Update: 1998-07-17 <jhy@gsu.edu>
9 * Added text <special options> to usage().
10 */
11 /**********************************************************************
12 Copyright 1997 Niels Baggesen
13
14 All Rights Reserved
15
16 Permission to use, copy, modify, and distribute this software and its
17 documentation for any purpose and without fee is hereby granted,
18 provided that the above copyright notice appear in all copies.
19
20 I DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22 I BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 SOFTWARE.
27 ******************************************************************/
28 #include <net-snmp/net-snmp-config.h>
29
30 #if HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33 #if HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #if HAVE_STRING_H
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41 #include <sys/types.h>
42 #if HAVE_NETINET_IN_H
43 # include <netinet/in.h>
44 #endif
45 #if TIME_WITH_SYS_TIME
46 # include <sys/time.h>
47 # include <time.h>
48 #else
49 # if HAVE_SYS_TIME_H
50 # include <sys/time.h>
51 # else
52 # include <time.h>
53 # endif
54 #endif
55 #if HAVE_SYS_SELECT_H
56 #include <sys/select.h>
57 #endif
58 #include <stdio.h>
59 #if HAVE_NETDB_H
60 #include <netdb.h>
61 #endif
62 #if HAVE_ARPA_INET_H
63 #include <arpa/inet.h>
64 #endif
65
66 #include <net-snmp/net-snmp-includes.h>
67
68 struct column {
69 int width;
70 oid subid;
71 char *label;
72 char *fmt;
73 } *column = NULL;
74
75 static char **data = NULL;
76 static char **indices = NULL;
77 static int index_width = sizeof("index ") - 1;
78 static int fields;
79 static int entries;
80 static int allocated;
81 static int end_of_table = 1;
82 static int headers_only = 0;
83 static int no_headers = 0;
84 static int max_width = 0;
85 static int column_width = 0;
86 static int brief = 0;
87 static int show_index = 0;
88 static const char *left_justify_flag = "";
89 static char *field_separator = NULL;
90 static char *table_name;
91 static oid name[MAX_OID_LEN];
92 static size_t name_length;
93 static oid root[MAX_OID_LEN];
94 static size_t rootlen;
95 static int localdebug;
96 static int exitval = 1;
97 static int use_getbulk = 1;
98 static int max_getbulk = 10;
99 static int extra_columns = 0;
100
101 void usage(void);
102 void get_field_names(void);
103 void get_table_entries(netsnmp_session * ss);
104 void getbulk_table_entries(netsnmp_session * ss);
105 void print_table(void);
106
107 static void
optProc(int argc,char * const * argv,int opt)108 optProc(int argc, char *const *argv, int opt)
109 {
110 switch (opt) {
111 case 'C':
112 /*
113 * Handle new '-C' command-specific meta-options
114 */
115 while (*optarg) {
116 switch (*optarg++) {
117 case 'w':
118 if (optind < argc) {
119 if (argv[optind]) {
120 max_width = atoi(argv[optind]);
121 if (max_width == 0) {
122 usage();
123 fprintf(stderr, "Bad -Cw option: %s\n",
124 argv[optind]);
125 exit(1);
126 }
127 }
128 } else {
129 usage();
130 fprintf(stderr, "Bad -Cw option: no argument given\n");
131 exit(1);
132 }
133 optind++;
134 break;
135 case 'c':
136 if (optind < argc) {
137 if (argv[optind]) {
138 column_width = atoi(argv[optind]);
139 if (column_width <= 2) {
140 usage();
141 fprintf(stderr, "Bad -Cc option: %s\n",
142 argv[optind]);
143 exit(1);
144 }
145 /* Reduce by one for space at end of column */
146 column_width -= 1;
147 }
148 } else {
149 usage();
150 fprintf(stderr, "Bad -Cc option: no argument given\n");
151 exit(1);
152 }
153 optind++;
154 break;
155 case 'l':
156 left_justify_flag = "-";
157 break;
158 case 'f':
159 if (optind < argc) {
160 field_separator = argv[optind];
161 } else {
162 usage();
163 fprintf(stderr, "Bad -Cf option: no argument given\n");
164 exit(1);
165 }
166 optind++;
167 break;
168 case 'h':
169 headers_only = 1;
170 break;
171 case 'H':
172 no_headers = 1;
173 break;
174 case 'B':
175 use_getbulk = 0;
176 break;
177 case 'b':
178 brief = 1;
179 break;
180 case 'i':
181 show_index = 1;
182 break;
183 case 'r':
184 if (optind < argc) {
185 if (argv[optind]) {
186 max_getbulk = atoi(argv[optind]);
187 if (max_getbulk == 0) {
188 usage();
189 fprintf(stderr, "Bad -Cr option: %s\n",
190 argv[optind]);
191 exit(1);
192 }
193 }
194 } else {
195 usage();
196 fprintf(stderr, "Bad -Cr option: no argument given\n");
197 exit(1);
198 }
199 optind++;
200 break;
201 default:
202 fprintf(stderr, "Bad option after -C: %c\n", optarg[-1]);
203 usage();
204 exit(1);
205 }
206 }
207 break;
208 }
209 }
210
211 void
usage(void)212 usage(void)
213 {
214 fprintf(stderr, "USAGE: snmptable ");
215 snmp_parse_args_usage(stderr);
216 fprintf(stderr, " TABLE-OID\n\n");
217 snmp_parse_args_descriptions(stderr);
218 fprintf(stderr,
219 " -C APPOPTS\t\tSet various application specific behaviours:\n");
220 fprintf(stderr, "\t\t\t b: brief field names\n");
221 fprintf(stderr, "\t\t\t B: do not use GETBULK requests\n");
222 fprintf(stderr, "\t\t\t c<NUM>: print table in columns of <NUM> chars width\n");
223 fprintf(stderr, "\t\t\t f<STR>: print table delimitied with <STR>\n");
224 fprintf(stderr, "\t\t\t h: print only the column headers\n");
225 fprintf(stderr, "\t\t\t H: print no column headers\n");
226 fprintf(stderr, "\t\t\t i: print index values\n");
227 fprintf(stderr, "\t\t\t l: left justify output\n");
228 fprintf(stderr, "\t\t\t r<NUM>: for GETBULK: set max-repeaters to <NUM>\n");
229 fprintf(stderr, "\t\t\t for GETNEXT: retrieve <NUM> entries at a time\n");
230 fprintf(stderr, "\t\t\t w<NUM>: print table in parts of <NUM> chars width\n");
231 }
232
233 void
reverse_fields(void)234 reverse_fields(void)
235 {
236 struct column tmp;
237 int i;
238
239 for (i = 0; i < fields / 2; i++) {
240 memcpy(&tmp, &(column[i]), sizeof(struct column));
241 memcpy(&(column[i]), &(column[fields - 1 - i]),
242 sizeof(struct column));
243 memcpy(&(column[fields - 1 - i]), &tmp, sizeof(struct column));
244 }
245 }
246
247 int
main(int argc,char * argv[])248 main(int argc, char *argv[])
249 {
250 netsnmp_session session, *ss;
251 int total_entries = 0;
252
253 SOCK_STARTUP;
254
255 netsnmp_set_line_buffering(stdout);
256
257 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
258 NETSNMP_DS_LIB_QUICK_PRINT, 1);
259
260 /*
261 * get the common command line arguments
262 */
263 switch (snmp_parse_args(argc, argv, &session, "C:", optProc)) {
264 case NETSNMP_PARSE_ARGS_ERROR:
265 goto out;
266 case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
267 exitval = 0;
268 goto out;
269 case NETSNMP_PARSE_ARGS_ERROR_USAGE:
270 usage();
271 goto out;
272 default:
273 break;
274 }
275
276 /*
277 * get the initial object and subtree
278 */
279 /*
280 * specified on the command line
281 */
282 if (optind + 1 != argc) {
283 fprintf(stderr, "Must have exactly one table name\n");
284 usage();
285 goto out;
286 }
287
288 rootlen = MAX_OID_LEN;
289 if (!snmp_parse_oid(argv[optind], root, &rootlen)) {
290 snmp_perror(argv[optind]);
291 goto out;
292 }
293 localdebug = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
294 NETSNMP_DS_LIB_DUMP_PACKET);
295
296 get_field_names();
297 reverse_fields();
298
299 /*
300 * open an SNMP session
301 */
302 ss = snmp_open(&session);
303 if (ss == NULL) {
304 /*
305 * diagnose snmp_open errors with the input netsnmp_session pointer
306 */
307 snmp_sess_perror("snmptable", &session);
308 goto out;
309 }
310
311 #ifndef NETSNMP_DISABLE_SNMPV1
312 if (ss->version == SNMP_VERSION_1)
313 use_getbulk = 0;
314 #endif
315
316 exitval = 0;
317
318 do {
319 entries = 0;
320 allocated = 0;
321 if (!headers_only) {
322 if (use_getbulk)
323 getbulk_table_entries(ss);
324 else
325 get_table_entries(ss);
326 }
327
328 if (exitval)
329 goto close_session;
330
331 if (entries || headers_only)
332 print_table();
333
334 if (data) {
335 int i, j;
336 for (i = 0; i < entries; i++)
337 for (j = 0; j < fields; j++)
338 free(data[i*fields+j]);
339 free (data);
340 data = NULL;
341 }
342
343 if (indices) {
344 int i;
345 for (i = 0; i < entries; i++)
346 free(indices[i]);
347 free (indices);
348 indices = NULL;
349 }
350
351 total_entries += entries;
352
353 } while (!end_of_table);
354
355 if (total_entries == 0)
356 printf("%s: No entries\n", table_name);
357 if (extra_columns)
358 printf("%s: WARNING: More columns on agent than in MIB\n", table_name);
359
360 exitval = 0;
361
362 close_session:
363 snmp_close(ss);
364
365 out:
366 SOCK_CLEANUP;
367 return exitval;
368 }
369
370 void
print_table(void)371 print_table(void)
372 {
373 int entry, field, first_field, last_field = 0, width, part = 0;
374 char **dp;
375 char string_buf[SPRINT_MAX_LEN];
376 char *index_fmt = NULL;
377 static int first_pass = 1;
378
379 if (!no_headers && !headers_only && first_pass)
380 printf("SNMP table: %s\n\n", table_name);
381
382 for (field = 0; field < fields; field++) {
383 if (column_width != 0)
384 sprintf(string_buf, "%%%s%d.%ds", left_justify_flag,
385 column_width + 1, column_width );
386 else if (field_separator == NULL)
387 sprintf(string_buf, "%%%s%ds", left_justify_flag,
388 column[field].width + 1);
389 else if (field == 0 && !show_index)
390 sprintf(string_buf, "%%s");
391 else
392 sprintf(string_buf, "%s%%s", field_separator);
393 column[field].fmt = strdup(string_buf);
394 }
395 if (show_index) {
396 if (column_width)
397 sprintf(string_buf, "\nindex: %%s\n");
398 else if (field_separator == NULL)
399 sprintf(string_buf, "%%%s%ds", left_justify_flag, index_width);
400 else
401 sprintf(string_buf, "%%s");
402 index_fmt = strdup(string_buf);
403 }
404
405 while (last_field != fields) {
406 part++;
407 if (part != 1 && !no_headers)
408 printf("\nSNMP table %s, part %d\n\n", table_name, part);
409 first_field = last_field;
410 dp = data;
411 if (show_index && !no_headers && !column_width && first_pass) {
412 width = index_width;
413 printf(index_fmt, "index");
414 } else
415 width = 0;
416 for (field = first_field; field < fields; field++) {
417 if (max_width)
418 {
419 if (column_width) {
420 if (!no_headers && first_pass) {
421 width += column_width + 1;
422 if (field != first_field && width > max_width) {
423 printf("\n");
424 width = column_width + 1;
425 }
426 }
427 }
428 else {
429 width += column[field].width + 1;
430 if (field != first_field && width > max_width)
431 break;
432 }
433 }
434 if (!no_headers && first_pass)
435 printf(column[field].fmt, column[field].label);
436 }
437 last_field = field;
438 if (!no_headers && first_pass)
439 printf("\n");
440 for (entry = 0; entry < entries; entry++) {
441 width = 0;
442 if (show_index)
443 {
444 if (!column_width)
445 width = index_width;
446 printf(index_fmt, indices[entry]);
447 }
448 for (field = first_field; field < last_field; field++) {
449 if (column_width && max_width) {
450 width += column_width + 1;
451 if (field != first_field && width > max_width) {
452 printf("\n");
453 width = column_width + 1;
454 }
455 }
456 printf(column[field].fmt, dp[field] ? dp[field] : "?");
457 }
458 dp += fields;
459 printf("\n");
460 }
461 }
462
463 first_pass = 0;
464 if (index_fmt)
465 free(index_fmt);
466 }
467
468 void
get_field_names(void)469 get_field_names(void)
470 {
471 char *buf = NULL, *name_p = NULL;
472 size_t buf_len = 0, out_len = 0;
473 #ifndef NETSNMP_DISABLE_MIB_LOADING
474 struct tree *tbl = NULL;
475 #endif /* NETSNMP_DISABLE_MIB_LOADING */
476 int going = 1;
477
478 #ifndef NETSNMP_DISABLE_MIB_LOADING
479 tbl = get_tree(root, rootlen, get_tree_head());
480 if (tbl) {
481 tbl = tbl->child_list;
482 if (tbl) {
483 root[rootlen++] = tbl->subid;
484 tbl = tbl->child_list;
485 } else {
486 root[rootlen++] = 1;
487 going = 0;
488 }
489 }
490 #endif /* NETSNMP_DISABLE_MIB_LOADING */
491
492 if (sprint_realloc_objid
493 ((u_char **)&buf, &buf_len, &out_len, 1, root, rootlen - 1)) {
494 table_name = buf;
495 buf = NULL;
496 buf_len = out_len = 0;
497 } else {
498 table_name = strdup("[TRUNCATED]");
499 out_len = 0;
500 }
501
502 fields = 0;
503 while (going) {
504 fields++;
505 #ifndef NETSNMP_DISABLE_MIB_LOADING
506 if (tbl) {
507 if (tbl->access == MIB_ACCESS_NOACCESS) {
508 fields--;
509 tbl = tbl->next_peer;
510 if (!tbl) {
511 going = 0;
512 }
513 continue;
514 }
515 root[rootlen] = tbl->subid;
516 tbl = tbl->next_peer;
517 if (!tbl)
518 going = 0;
519 } else {
520 #endif /* NETSNMP_DISABLE_MIB_LOADING */
521 root[rootlen] = fields;
522 #ifndef NETSNMP_DISABLE_MIB_LOADING
523 }
524 #endif /* NETSNMP_DISABLE_MIB_LOADING */
525 out_len = 0;
526 if (sprint_realloc_objid
527 ((u_char **)&buf, &buf_len, &out_len, 1, root, rootlen + 1)) {
528 name_p = strrchr(buf, '.');
529 if (name_p == NULL) {
530 name_p = strrchr(buf, ':');
531 }
532 if (name_p == NULL) {
533 name_p = buf;
534 } else {
535 name_p++;
536 }
537 } else {
538 break;
539 }
540 if (localdebug) {
541 printf("%s %c\n", buf, name_p[0]);
542 }
543 if ('0' <= name_p[0] && name_p[0] <= '9') {
544 fields--;
545 break;
546 }
547 if (fields == 1) {
548 column = (struct column *) malloc(sizeof(*column));
549 } else {
550 column =
551 (struct column *) realloc(column,
552 fields * sizeof(*column));
553 }
554 column[fields - 1].label = strdup(name_p);
555 column[fields - 1].width = strlen(name_p);
556 column[fields - 1].subid = root[rootlen];
557 }
558 if (fields == 0) {
559 fprintf(stderr, "Was that a table? %s\n", table_name);
560 exit(1);
561 }
562 if (name_p) {
563 *name_p = 0;
564 memmove(name, root, rootlen * sizeof(oid));
565 name_length = rootlen + 1;
566 name_p = strrchr(buf, '.');
567 if (name_p == NULL) {
568 name_p = strrchr(buf, ':');
569 }
570 if (name_p != NULL) {
571 *name_p = 0;
572 }
573 }
574 if (brief && fields > 1) {
575 char *f1, *f2;
576 int common = strlen(column[0].label);
577 int field, len;
578 for (field = 1; field < fields; field++) {
579 f1 = column[field - 1].label;
580 f2 = column[field].label;
581 while (*f1 && *f1++ == *f2++);
582 len = f2 - column[field].label - 1;
583 if (len < common)
584 common = len;
585 }
586 if (common) {
587 for (field = 0; field < fields; field++) {
588 column[field].label += common;
589 column[field].width -= common;
590 }
591 }
592 }
593 if (buf != NULL) {
594 free(buf);
595 }
596 }
597
598 void
get_table_entries(netsnmp_session * ss)599 get_table_entries(netsnmp_session * ss)
600 {
601 int running = 1;
602 netsnmp_pdu *pdu, *response;
603 netsnmp_variable_list *vars;
604 int count;
605 int status;
606 int i;
607 int col;
608 char *buf = NULL;
609 size_t out_len = 0, buf_len = 0;
610 char *cp;
611 char *name_p = NULL;
612 char **dp;
613 int have_current_index;
614
615 /*
616 * TODO:
617 * 1) Deal with multiple index fields
618 * 2) Deal with variable length index fields
619 * 3) optimize to remove a sparse column from get-requests
620 */
621
622 while (running &&
623 ((max_width && !column_width) || (entries < max_getbulk))) {
624 /*
625 * create PDU for GETNEXT request and add object name to request
626 */
627 pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
628 for (i = 1; i <= fields; i++) {
629 name[rootlen] = column[i - 1].subid;
630 snmp_add_null_var(pdu, name, name_length);
631 }
632
633 /*
634 * do the request
635 */
636 status = snmp_synch_response(ss, pdu, &response);
637 if (status == STAT_SUCCESS) {
638 if (response->errstat == SNMP_ERR_NOERROR) {
639 /*
640 * check resulting variables
641 */
642 vars = response->variables;
643 entries++;
644 if (entries >= allocated) {
645 if (allocated == 0) {
646 allocated = 10;
647 data =
648 (char **) malloc(allocated * fields *
649 sizeof(char *));
650 memset(data, 0,
651 allocated * fields * sizeof(char *));
652 if (show_index)
653 indices =
654 (char **) malloc(allocated *
655 sizeof(char *));
656 } else {
657 allocated += 10;
658 data =
659 (char **) realloc(data,
660 allocated * fields *
661 sizeof(char *));
662 memset(data + entries * fields, 0,
663 (allocated -
664 entries) * fields * sizeof(char *));
665 if (show_index)
666 indices =
667 (char **) realloc(indices,
668 allocated *
669 sizeof(char *));
670 }
671 }
672 dp = data + (entries - 1) * fields;
673 col = -1;
674 end_of_table = 1; /* assume end of table */
675 have_current_index = 0;
676 name_length = rootlen + 1;
677 for (vars = response->variables; vars;
678 vars = vars->next_variable) {
679 col++;
680 name[rootlen] = column[col].subid;
681 if ((vars->name_length < name_length) ||
682 (vars->name[rootlen] != column[col].subid) ||
683 memcmp(name, vars->name,
684 name_length * sizeof(oid)) != 0
685 || vars->type == SNMP_ENDOFMIBVIEW) {
686 /*
687 * not part of this subtree
688 */
689 if (localdebug) {
690 fprint_variable(stderr, vars->name,
691 vars->name_length, vars);
692 fprintf(stderr, " => ignored\n");
693 }
694 continue;
695 }
696
697 /*
698 * save index off
699 */
700 if (!have_current_index) {
701 end_of_table = 0;
702 have_current_index = 1;
703 name_length = vars->name_length;
704 memcpy(name, vars->name,
705 name_length * sizeof(oid));
706 out_len = 0;
707 if (!sprint_realloc_objid
708 ((u_char **)&buf, &buf_len, &out_len, 1, vars->name,
709 vars->name_length)) {
710 break;
711 }
712 if (localdebug || show_index) {
713 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
714 NETSNMP_DS_LIB_EXTENDED_INDEX)) {
715 name_p = strchr(buf, '[');
716 } else {
717 switch (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
718 NETSNMP_DS_LIB_OID_OUTPUT_FORMAT)) {
719 case NETSNMP_OID_OUTPUT_MODULE:
720 case 0:
721 name_p = strchr(buf, ':');
722 break;
723 case NETSNMP_OID_OUTPUT_SUFFIX:
724 name_p = buf;
725 break;
726 case NETSNMP_OID_OUTPUT_FULL:
727 case NETSNMP_OID_OUTPUT_NUMERIC:
728 case NETSNMP_OID_OUTPUT_UCD:
729 name_p = buf + strlen(table_name)+1;
730 name_p = strchr(name_p, '.')+1;
731 break;
732 default:
733 fprintf(stderr, "Unrecognized -O option: %d\n",
734 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
735 NETSNMP_DS_LIB_OID_OUTPUT_FORMAT));
736 exit(1);
737 }
738 name_p = strchr(name_p, '.') + 1;
739 }
740 }
741 if (localdebug) {
742 printf("Name: %s Index: %s\n", buf, name_p);
743 }
744 if (show_index) {
745 indices[entries - 1] = strdup(name_p);
746 i = strlen(name_p);
747 if (i > index_width)
748 index_width = i;
749 }
750 }
751
752 if (localdebug && buf) {
753 printf("%s => taken\n", buf);
754 }
755 if (dp[col]) {
756 fprintf(stderr, "OID not increasing: %s\n", buf);
757 running = 0;
758 vars = NULL;
759 end_of_table = 1;
760 exitval = 2;
761 break;
762 }
763 out_len = 0;
764 sprint_realloc_value((u_char **)&buf, &buf_len, &out_len, 1,
765 vars->name, vars->name_length,
766 vars);
767 for (cp = buf; *cp; cp++) {
768 if (*cp == '\n') {
769 *cp = ' ';
770 }
771 }
772 dp[col] = buf;
773 i = out_len;
774 buf = NULL;
775 buf_len = 0;
776 if (i > column[col].width) {
777 column[col].width = i;
778 }
779 }
780 if (buf) {
781 free(buf);
782 buf = NULL;
783 buf_len = 0;
784 }
785
786 if (end_of_table) {
787 --entries;
788 /*
789 * not part of this subtree
790 */
791 if (localdebug) {
792 printf("End of table\n");
793 }
794 snmp_free_pdu(response);
795 running = 0;
796 continue;
797 }
798 } else {
799 /*
800 * error in response, print it
801 */
802 running = 0;
803 if (response->errstat == SNMP_ERR_NOSUCHNAME) {
804 printf("End of MIB\n");
805 end_of_table = 1;
806 } else {
807 fprintf(stderr, "Error in packet.\nReason: %s\n",
808 snmp_errstring(response->errstat));
809 if (response->errindex != 0) {
810 fprintf(stderr, "Failed object: ");
811 for (count = 1, vars = response->variables;
812 vars && count != response->errindex;
813 vars = vars->next_variable, count++)
814 /*EMPTY*/;
815 if (vars) {
816 fprint_objid(stderr, vars->name,
817 vars->name_length);
818 }
819 fprintf(stderr, "\n");
820 }
821 exitval = 2;
822 }
823 }
824 } else if (status == STAT_TIMEOUT) {
825 fprintf(stderr, "Timeout: No Response from %s\n",
826 ss->peername);
827 running = 0;
828 exitval = 1;
829 } else { /* status == STAT_ERROR */
830 snmp_sess_perror("snmptable", ss);
831 running = 0;
832 exitval = 1;
833 }
834 if (response)
835 snmp_free_pdu(response);
836 }
837 }
838
839 void
getbulk_table_entries(netsnmp_session * ss)840 getbulk_table_entries(netsnmp_session * ss)
841 {
842 int running = 1;
843 netsnmp_pdu *pdu, *response;
844 netsnmp_variable_list *vars, *last_var;
845 int count;
846 int status;
847 int i;
848 int row, col;
849 char *buf = NULL;
850 size_t buf_len = 0, out_len = 0;
851 char *cp;
852 char *name_p = NULL;
853 char **dp;
854
855 while (running) {
856 /*
857 * create PDU for GETBULK request and add object name to request
858 */
859 pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
860 pdu->non_repeaters = 0;
861 pdu->max_repetitions = max_getbulk;
862 snmp_add_null_var(pdu, name, name_length);
863
864 /*
865 * do the request
866 */
867 status = snmp_synch_response(ss, pdu, &response);
868 if (status == STAT_SUCCESS) {
869 if (response->errstat == SNMP_ERR_NOERROR) {
870 /*
871 * check resulting variables
872 */
873 vars = response->variables;
874 last_var = NULL;
875 while (vars) {
876 out_len = 0;
877 sprint_realloc_objid((u_char **)&buf, &buf_len, &out_len, 1,
878 vars->name, vars->name_length);
879 if (vars->type == SNMP_ENDOFMIBVIEW ||
880 memcmp(vars->name, name,
881 rootlen * sizeof(oid)) != 0) {
882 if (localdebug) {
883 printf("%s => end of table\n",
884 buf ? (char *) buf : "[NIL]");
885 }
886 running = 0;
887 break;
888 }
889 if (localdebug) {
890 printf("%s => taken\n",
891 buf ? (char *) buf : "[NIL]");
892 }
893 for (col = 0; col < fields; col++)
894 if (column[col].subid == vars->name[rootlen])
895 break;
896 if (col == fields) {
897 extra_columns = 1;
898 last_var = vars;
899 vars = vars->next_variable;
900 continue;
901 }
902 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
903 NETSNMP_DS_LIB_EXTENDED_INDEX)) {
904 name_p = strchr(buf, '[');
905 if (name_p == NULL) {
906 running = 0;
907 break;
908 }
909 } else {
910 switch (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
911 NETSNMP_DS_LIB_OID_OUTPUT_FORMAT)) {
912 case NETSNMP_OID_OUTPUT_MODULE:
913 case 0:
914 name_p = strchr(buf, ':')+1;
915 break;
916 case NETSNMP_OID_OUTPUT_SUFFIX:
917 name_p = buf;
918 break;
919 case NETSNMP_OID_OUTPUT_FULL:
920 case NETSNMP_OID_OUTPUT_NUMERIC:
921 case NETSNMP_OID_OUTPUT_UCD:
922 name_p = buf + strlen(table_name)+1;
923 name_p = strchr(name_p, '.')+1;
924 break;
925 default:
926 fprintf(stderr, "Unrecognized -O option: %d\n",
927 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
928 NETSNMP_DS_LIB_OID_OUTPUT_FORMAT));
929 exit(1);
930 }
931 name_p = strchr(name_p, '.');
932 if ( name_p == NULL ) {
933 /* The 'strchr' call above failed, i.e. the results
934 * don't seem to include instance subidentifiers! */
935 running = 0;
936 break;
937 }
938 name_p++; /* Move on to the instance identifier */
939 }
940 for (row = 0; row < entries; row++)
941 if (strcmp(name_p, indices[row]) == 0)
942 break;
943 if (row == entries) {
944 entries++;
945 if (entries >= allocated) {
946 if (allocated == 0) {
947 allocated = 10;
948 data =
949 (char **) malloc(allocated * fields *
950 sizeof(char *));
951 memset(data, 0,
952 allocated * fields *
953 sizeof(char *));
954 indices =
955 (char **) malloc(allocated *
956 sizeof(char *));
957 } else {
958 allocated += 10;
959 data =
960 (char **) realloc(data,
961 allocated * fields *
962 sizeof(char *));
963 memset(data + entries * fields, 0,
964 (allocated -
965 entries) * fields *
966 sizeof(char *));
967 indices =
968 (char **) realloc(indices,
969 allocated *
970 sizeof(char *));
971 }
972 }
973 indices[row] = strdup(name_p);
974 i = strlen(name_p);
975 if (i > index_width)
976 index_width = i;
977 }
978 dp = data + row * fields;
979 if (dp[col]) {
980 fprintf(stderr, "OID not increasing: %s\n", buf);
981 exitval = 2;
982 end_of_table = 1;
983 running = 0;
984 break;
985 }
986 out_len = 0;
987 sprint_realloc_value((u_char **)&buf, &buf_len, &out_len, 1,
988 vars->name, vars->name_length,
989 vars);
990 for (cp = buf; *cp; cp++)
991 if (*cp == '\n')
992 *cp = ' ';
993 dp[col] = buf;
994 i = out_len;
995 buf = NULL;
996 buf_len = 0;
997 if (i > column[col].width)
998 column[col].width = i;
999 last_var = vars;
1000 vars = vars->next_variable;
1001 }
1002 if (last_var) {
1003 name_length = last_var->name_length;
1004 memcpy(name, last_var->name,
1005 name_length * sizeof(oid));
1006 }
1007 if (buf) {
1008 free(buf);
1009 buf = NULL;
1010 buf_len = 0;
1011 }
1012 } else {
1013 /*
1014 * error in response, print it
1015 */
1016 running = 0;
1017 if (response->errstat == SNMP_ERR_NOSUCHNAME) {
1018 printf("End of MIB\n");
1019 } else {
1020 fprintf(stderr, "Error in packet.\nReason: %s\n",
1021 snmp_errstring(response->errstat));
1022 if (response->errstat == SNMP_ERR_NOSUCHNAME) {
1023 fprintf(stderr,
1024 "The request for this object identifier failed: ");
1025 for (count = 1, vars = response->variables;
1026 vars && count != response->errindex;
1027 vars = vars->next_variable, count++)
1028 /*EMPTY*/;
1029 if (vars) {
1030 fprint_objid(stderr, vars->name,
1031 vars->name_length);
1032 }
1033 fprintf(stderr, "\n");
1034 }
1035 exitval = 2;
1036 }
1037 }
1038 } else if (status == STAT_TIMEOUT) {
1039 fprintf(stderr, "Timeout: No Response from %s\n",
1040 ss->peername);
1041 running = 0;
1042 exitval = 1;
1043 } else { /* status == STAT_ERROR */
1044 snmp_sess_perror("snmptable", ss);
1045 running = 0;
1046 exitval = 1;
1047 }
1048 if (response)
1049 snmp_free_pdu(response);
1050 }
1051 }
1052