added files
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmptable.c
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 # ifdef WIN32
47 #  include <sys/timeb.h>
48 # else
49 #  include <sys/time.h>
50 # endif
51 # include <time.h>
52 #else
53 # if HAVE_SYS_TIME_H
54 #  include <sys/time.h>
55 # else
56 #  include <time.h>
57 # endif
58 #endif
59 #if HAVE_SYS_SELECT_H
60 #include <sys/select.h>
61 #endif
62 #include <stdio.h>
63 #if HAVE_WINSOCK_H
64 #include <winsock.h>
65 #endif
66 #if HAVE_NETDB_H
67 #include <netdb.h>
68 #endif
69 #if HAVE_ARPA_INET_H
70 #include <arpa/inet.h>
71 #endif
72
73 #include <net-snmp/net-snmp-includes.h>
74
75 struct column {
76     int             width;
77     oid             subid;
78     char           *label;
79     char           *fmt;
80 }              *column = NULL;
81
82 static char   **data = NULL;
83 static char   **indices = NULL;
84 static int      index_width = sizeof("index") - 1;
85 static int      fields;
86 static int      entries;
87 static int      allocated;
88 static int      headers_only = 0;
89 static int      no_headers = 0;
90 static int      max_width = 0;
91 static int      brief = 0;
92 static int      show_index = 0;
93 static char    *field_separator = NULL;
94 static char    *table_name;
95 static oid      name[MAX_OID_LEN];
96 static size_t   name_length;
97 static oid      root[MAX_OID_LEN];
98 static size_t   rootlen;
99 static int      localdebug;
100 static int      exitval = 0;
101 static int      use_getbulk = 1;
102 static int      max_getbulk = 25;
103
104 void            usage(void);
105 void            get_field_names(char *);
106 void            get_table_entries(netsnmp_session * ss);
107 void            getbulk_table_entries(netsnmp_session * ss);
108 void            print_table(void);
109
110 static void
111 optProc(int argc, char *const *argv, int opt)
112 {
113     switch (opt) {
114     case 'C':
115         /*
116          * Handle new '-C' command-specific meta-options 
117          */
118         while (*optarg) {
119             switch (*optarg++) {
120             case 'w':
121                 if (optind < argc) {
122                     if (argv[optind]) {
123                         max_width = atoi(argv[optind]);
124                         if (max_width == 0) {
125                             usage();
126                             fprintf(stderr, "Bad -Cw option: %s\n", 
127                                     argv[optind]);
128                             exit(1);
129                         }
130                     }
131                 } else {
132                     usage();
133                     fprintf(stderr, "Bad -Cw option: no argument given\n");
134                     exit(1);
135                 }
136                 optind++;
137                 break;
138             case 'f':
139                 if (optind < argc) {
140                     field_separator = argv[optind];
141                 } else {
142                     usage();
143                     fprintf(stderr, "Bad -Cf option: no argument given\n");
144                     exit(1);
145                 }
146                 optind++;
147                 break;
148             case 'h':
149                 headers_only = 1;
150                 break;
151             case 'H':
152                 no_headers = 1;
153                 break;
154             case 'B':
155                 use_getbulk = 0;
156                 break;
157             case 'b':
158                 brief = 1;
159                 break;
160             case 'i':
161                 show_index = 1;
162                 break;
163             default:
164                 fprintf(stderr, "Bad option after -C: %c\n", optarg[-1]);
165                 usage();
166             }
167         }
168         break;
169     }
170 }
171
172 void
173 usage(void)
174 {
175     fprintf(stderr, "USAGE: snmptable ");
176     snmp_parse_args_usage(stderr);
177     fprintf(stderr, " TABLE-OID\n\n");
178     snmp_parse_args_descriptions(stderr);
179     fprintf(stderr,
180             "  -C APPOPTS\t\tSet various application specific behaviours:\n");
181     fprintf(stderr, "\t\t\t  b:       brief field names\n");
182     fprintf(stderr, "\t\t\t  B:       do not use GETBULK requests\n");
183     fprintf(stderr, "\t\t\t  f<STR>:  print table delimitied with <STR>\n");
184     fprintf(stderr, "\t\t\t  h:       print only the column headers\n");
185     fprintf(stderr, "\t\t\t  H:       print no column headers\n");
186     fprintf(stderr, "\t\t\t  i:       print index values\n");
187     fprintf(stderr, "\t\t\t  w<NUM>:  print table in parts of <NUM> chars width\n");
188 }
189
190 void
191 reverse_fields(void)
192 {
193     struct column   tmp;
194     int             i;
195
196     for (i = 0; i < fields / 2; i++) {
197         memcpy(&tmp, &(column[i]), sizeof(struct column));
198         memcpy(&(column[i]), &(column[fields - 1 - i]),
199                sizeof(struct column));
200         memcpy(&(column[fields - 1 - i]), &tmp, sizeof(struct column));
201     }
202 }
203
204 int
205 main(int argc, char *argv[])
206 {
207     netsnmp_session session, *ss;
208     char           *tblname;
209
210     setvbuf(stdout, NULL, _IOLBF, 1024);
211     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
212                            NETSNMP_DS_LIB_QUICK_PRINT, 1);
213
214     /*
215      * get the common command line arguments 
216      */
217     switch (snmp_parse_args(argc, argv, &session, "C:", optProc)) {
218     case -2:
219         exit(0);
220     case -1:
221         usage();
222         exit(1);
223     default:
224         break;
225     }
226
227     /*
228      * get the initial object and subtree 
229      */
230     /*
231      * specified on the command line 
232      */
233     if (optind + 1 != argc) {
234         fprintf(stderr, "Must have exactly one table name\n");
235         usage();
236     }
237
238     rootlen = MAX_OID_LEN;
239     if (!snmp_parse_oid(argv[optind], root, &rootlen)) {
240         snmp_perror(argv[optind]);
241         exit(1);
242     }
243     localdebug = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
244                                         NETSNMP_DS_LIB_DUMP_PACKET);
245     tblname = strrchr(argv[optind], '.');
246     if (!tblname)
247         tblname = strrchr(argv[optind], ':');
248     if (tblname)
249         ++tblname;
250     else
251         tblname = argv[optind];
252
253     get_field_names(tblname);
254     reverse_fields();
255
256     /*
257      * open an SNMP session 
258      */
259     SOCK_STARTUP;
260     ss = snmp_open(&session);
261     if (ss == NULL) {
262         /*
263          * diagnose snmp_open errors with the input netsnmp_session pointer 
264          */
265         snmp_sess_perror("snmptable", &session);
266         SOCK_CLEANUP;
267         exit(1);
268     }
269
270     if (ss->version == SNMP_VERSION_1)
271         use_getbulk = 0;
272     if (!headers_only) {
273         if (use_getbulk)
274             getbulk_table_entries(ss);
275         else
276             get_table_entries(ss);
277     }
278
279     snmp_close(ss);
280     SOCK_CLEANUP;
281     if (exitval)
282         return exitval;
283
284     if (entries || headers_only)
285         print_table();
286     else
287         printf("%s: No entries\n", table_name);
288
289     return 0;
290 }
291
292 void
293 print_table(void)
294 {
295     int             entry, field, first_field, last_field =
296         0, width, part = 0;
297     char          **dp;
298     char            string_buf[SPRINT_MAX_LEN];
299     char           *index_fmt = NULL;
300
301     if (!no_headers && !headers_only)
302         printf("SNMP table: %s\n\n", table_name);
303
304     for (field = 0; field < fields; field++) {
305         if (field_separator == NULL)
306             sprintf(string_buf, "%%%ds", column[field].width + 1);
307         else if (field == 0 && !show_index)
308             sprintf(string_buf, "%%s");
309         else
310             sprintf(string_buf, "%s%%s", field_separator);
311         column[field].fmt = strdup(string_buf);
312     }
313     if (show_index) {
314         if (field_separator == NULL)
315             sprintf(string_buf, "%%%ds", index_width);
316         else
317             sprintf(string_buf, "%%s");
318         index_fmt = strdup(string_buf);
319     }
320
321     while (last_field != fields) {
322         part++;
323         if (part != 1 && !no_headers)
324             printf("\nSNMP table %s, part %d\n\n", table_name, part);
325         first_field = last_field;
326         dp = data;
327         if (show_index && !no_headers) {
328             width = index_width;
329             printf(index_fmt, "index");
330         } else
331             width = 0;
332         for (field = first_field; field < fields; field++) {
333             width += column[field].width + 1;
334             if (field != first_field && width > max_width
335                 && max_width != 0)
336                 break;
337             if (!no_headers)
338                 printf(column[field].fmt, column[field].label);
339         }
340         last_field = field;
341         if (!no_headers)
342             printf("\n");
343         for (entry = 0; entry < entries; entry++) {
344             if (show_index)
345                 printf(index_fmt, indices[entry]);
346             for (field = first_field; field < last_field; field++) {
347                 printf(column[field].fmt, dp[field] ? dp[field] : "?");
348             }
349             dp += fields;
350             printf("\n");
351         }
352     }
353 }
354
355 void
356 get_field_names(char *tblname)
357 {
358     u_char         *buf = NULL, *name_p = NULL;
359     size_t          buf_len = 0, out_len = 0;
360     struct tree    *tbl = NULL;
361     int             going = 1;
362
363     tbl = find_tree_node(tblname, -1);
364     if (tbl) {
365         tbl = tbl->child_list;
366         if (tbl) {
367             root[rootlen++] = tbl->subid;
368             tbl = tbl->child_list;
369         } else {
370             root[rootlen++] = 1;
371         }
372     }
373
374     if (sprint_realloc_objid
375         (&buf, &buf_len, &out_len, 1, root, rootlen - 1)) {
376         table_name = buf;
377         buf = NULL;
378         buf_len = out_len = 0;
379     } else {
380         table_name = strdup("[TRUNCATED]");
381         out_len = 0;
382     }
383
384     fields = 0;
385     while (going) {
386         fields++;
387         if (tbl) {
388             if (tbl->access == MIB_ACCESS_NOACCESS) {
389                 fields--;
390                 tbl = tbl->next_peer;
391                 if (!tbl) {
392                     going = 0;
393                 }
394                 continue;
395             }
396             root[rootlen] = tbl->subid;
397             tbl = tbl->next_peer;
398             if (!tbl)
399                 going = 0;
400         } else {
401             root[rootlen] = fields;
402         }
403         out_len = 0;
404         if (sprint_realloc_objid
405             (&buf, &buf_len, &out_len, 1, root, rootlen + 1)) {
406             name_p = strrchr(buf, '.');
407             if (name_p == NULL) {
408                 name_p = strrchr(buf, ':');
409             }
410             if (name_p == NULL) {
411                 name_p = buf;
412             } else {
413                 name_p++;
414             }
415         } else {
416             break;
417         }
418         if (localdebug) {
419             printf("%s %c\n", buf, name_p[0]);
420         }
421         if ('0' <= name_p[0] && name_p[0] <= '9') {
422             fields--;
423             break;
424         }
425         if (fields == 1) {
426             column = (struct column *) malloc(sizeof(*column));
427         } else {
428             column =
429                 (struct column *) realloc(column,
430                                           fields * sizeof(*column));
431         }
432         column[fields - 1].label = strdup(name_p);
433         column[fields - 1].width = strlen(name_p);
434         column[fields - 1].subid = root[rootlen];
435     }
436     if (fields == 0) {
437         fprintf(stderr, "Was that a table? %s\n", buf);
438         exit(1);
439     }
440     *name_p = 0;
441     memmove(name, root, rootlen * sizeof(oid));
442     name_length = rootlen + 1;
443     name_p = strrchr(buf, '.');
444     if (name_p == NULL) {
445         name_p = strrchr(buf, ':');
446     }
447     if (name_p != NULL) {
448         *name_p = 0;
449     }
450     if (brief && fields > 1) {
451         char           *f1, *f2;
452         int             common = strlen(column[0].label);
453         int             field, len;
454         for (field = 1; field < fields; field++) {
455             f1 = column[field - 1].label;
456             f2 = column[field].label;
457             while (*f1 && *f1++ == *f2++);
458             len = f2 - column[field].label - 1;
459             if (len < common)
460                 common = len;
461         }
462         if (common) {
463             for (field = 0; field < fields; field++) {
464                 column[field].label += common;
465                 column[field].width -= common;
466             }
467         }
468     }
469     if (buf != NULL) {
470         free(buf);
471     }
472 }
473
474 void
475 get_table_entries(netsnmp_session * ss)
476 {
477     int             running = 1;
478     netsnmp_pdu    *pdu, *response;
479     netsnmp_variable_list *vars;
480     int             count;
481     int             status;
482     int             i;
483     int             col;
484     u_char         *buf = NULL;
485     size_t          out_len = 0, buf_len = 0;
486     char           *cp;
487     char           *name_p = NULL;
488     char          **dp;
489     int             end_of_table = 0;
490     int             have_current_index;
491
492     /*
493      * TODO:
494      *   1) Deal with multiple index fields
495      *   2) Deal with variable length index fields
496      *   3) optimize to remove a sparse column from get-requests
497      */
498
499     while (running) {
500         /*
501          * create PDU for GETNEXT request and add object name to request 
502          */
503         pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
504         for (i = 1; i <= fields; i++) {
505             name[rootlen] = column[i - 1].subid;
506             snmp_add_null_var(pdu, name, name_length);
507         }
508
509         /*
510          * do the request 
511          */
512         status = snmp_synch_response(ss, pdu, &response);
513         if (status == STAT_SUCCESS) {
514             if (response->errstat == SNMP_ERR_NOERROR) {
515                 /*
516                  * check resulting variables 
517                  */
518                 vars = response->variables;
519                 entries++;
520                 if (entries >= allocated) {
521                     if (allocated == 0) {
522                         allocated = 10;
523                         data =
524                             (char **) malloc(allocated * fields *
525                                              sizeof(char *));
526                         memset(data, 0,
527                                allocated * fields * sizeof(char *));
528                         if (show_index)
529                             indices =
530                                 (char **) malloc(allocated *
531                                                  sizeof(char *));
532                     } else {
533                         allocated += 10;
534                         data =
535                             (char **) realloc(data,
536                                               allocated * fields *
537                                               sizeof(char *));
538                         memset(data + entries * fields, 0,
539                                (allocated -
540                                 entries) * fields * sizeof(char *));
541                         if (show_index)
542                             indices =
543                                 (char **) realloc(indices,
544                                                   allocated *
545                                                   sizeof(char *));
546                     }
547                 }
548                 dp = data + (entries - 1) * fields;
549                 col = -1;
550                 end_of_table = 1;       /* assume end of table */
551                 have_current_index = 0;
552                 name_length = rootlen + 1;
553                 for (vars = response->variables; vars;
554                      vars = vars->next_variable) {
555                     col++;
556                     name[rootlen] = column[col].subid;
557                     if ((vars->name_length < name_length) ||
558                         ((int) vars->name[rootlen] != column[col].subid) ||
559                         memcmp(name, vars->name,
560                                name_length * sizeof(oid)) != 0
561                         || vars->type == SNMP_ENDOFMIBVIEW) {
562                         /*
563                          * not part of this subtree 
564                          */
565                         if (localdebug) {
566                             fprint_variable(stderr, vars->name,
567                                             vars->name_length, vars);
568                             fprintf(stderr, " => ignored\n");
569                         }
570                         continue;
571                     }
572
573                     /*
574                      * save index off 
575                      */
576                     if (!have_current_index) {
577                         end_of_table = 0;
578                         have_current_index = 1;
579                         name_length = vars->name_length;
580                         memcpy(name, vars->name,
581                                name_length * sizeof(oid));
582                         out_len = 0;
583                         if (!sprint_realloc_objid
584                             (&buf, &buf_len, &out_len, 1, vars->name,
585                              vars->name_length)) {
586                             break;
587                         }
588                         i = vars->name_length - rootlen + 1;
589                         if (localdebug || show_index) {
590                             if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
591                                               NETSNMP_DS_LIB_EXTENDED_INDEX)) {
592                                 name_p = strchr(buf, '[');
593                             } else {
594                                 switch (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
595                                                           NETSNMP_DS_LIB_OID_OUTPUT_FORMAT)) {
596                                 case NETSNMP_OID_OUTPUT_MODULE:
597                                 case 0:
598                                     name_p = strrchr(buf, ':');
599                                     break;
600                                 case NETSNMP_OID_OUTPUT_SUFFIX:
601                                     name_p = buf;
602                                     break;
603                                 case NETSNMP_OID_OUTPUT_FULL:
604                                 case NETSNMP_OID_OUTPUT_NUMERIC:
605                                 case NETSNMP_OID_OUTPUT_UCD:
606                                     name_p = buf + strlen(table_name)+1;
607                                     name_p = strchr(name_p, '.')+1;
608                                     break;
609                                 default:
610                                     fprintf(stderr, "Unrecognized -O option: %d\n",
611                                             netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
612                                                               NETSNMP_DS_LIB_OID_OUTPUT_FORMAT));
613                                     exit(1);
614                                 }
615                                 name_p = strchr(name_p, '.') + 1;
616                             }
617                         }
618                         if (localdebug) {
619                             printf("Name: %s Index: %s\n", buf, name_p);
620                         }
621                         if (show_index) {
622                             indices[entries - 1] = strdup(name_p);
623                             i = strlen(name_p);
624                             if (i > index_width)
625                                 index_width = i;
626                         }
627                     }
628
629                     if (localdebug && buf) {
630                         printf("%s => taken\n", buf);
631                     }
632                     out_len = 0;
633                     sprint_realloc_value(&buf, &buf_len, &out_len, 1,
634                                          vars->name, vars->name_length,
635                                          vars);
636                     for (cp = buf; *cp; cp++) {
637                         if (*cp == '\n') {
638                             *cp = ' ';
639                         }
640                     }
641                     dp[col] = buf;
642                     i = out_len;
643                     buf = NULL;
644                     buf_len = 0;
645                     if (i > column[col].width) {
646                         column[col].width = i;
647                     }
648                 }
649
650                 if (end_of_table) {
651                     --entries;
652                     /*
653                      * not part of this subtree 
654                      */
655                     if (localdebug) {
656                         printf("End of table: %s\n",
657                                buf ? (char *) buf : "[NIL]");
658                     }
659                     running = 0;
660                     continue;
661                 }
662             } else {
663                 /*
664                  * error in response, print it 
665                  */
666                 running = 0;
667                 if (response->errstat == SNMP_ERR_NOSUCHNAME) {
668                     printf("End of MIB\n");
669                 } else {
670                     fprintf(stderr, "Error in packet.\nReason: %s\n",
671                             snmp_errstring(response->errstat));
672                     if (response->errindex != 0) {
673                         fprintf(stderr, "Failed object: ");
674                         for (count = 1, vars = response->variables;
675                              vars && count != response->errindex;
676                              vars = vars->next_variable, count++)
677                             /*EMPTY*/;
678                         if (vars) {
679                             fprint_objid(stderr, vars->name,
680                                          vars->name_length);
681                         }
682                         fprintf(stderr, "\n");
683                     }
684                     exitval = 2;
685                 }
686             }
687         } else if (status == STAT_TIMEOUT) {
688             fprintf(stderr, "Timeout: No Response from %s\n",
689                     ss->peername);
690             running = 0;
691             exitval = 1;
692         } else {                /* status == STAT_ERROR */
693             snmp_sess_perror("snmptable", ss);
694             running = 0;
695             exitval = 1;
696         }
697         if (response)
698             snmp_free_pdu(response);
699     }
700 }
701
702 void
703 getbulk_table_entries(netsnmp_session * ss)
704 {
705     int             running = 1;
706     netsnmp_pdu    *pdu, *response;
707     netsnmp_variable_list *vars, *last_var;
708     int             count;
709     int             status;
710     int             i;
711     int             row, col;
712     u_char         *buf = NULL;
713     size_t          buf_len = 0, out_len = 0;
714     char           *cp;
715     char           *name_p = NULL;
716     char          **dp;
717
718     while (running) {
719         /*
720          * create PDU for GETNEXT request and add object name to request 
721          */
722         pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
723         pdu->non_repeaters = 0;
724         pdu->max_repetitions = max_getbulk;
725         snmp_add_null_var(pdu, name, name_length);
726
727         /*
728          * do the request 
729          */
730         status = snmp_synch_response(ss, pdu, &response);
731         if (status == STAT_SUCCESS) {
732             if (response->errstat == SNMP_ERR_NOERROR) {
733                 /*
734                  * check resulting variables 
735                  */
736                 vars = response->variables;
737                 last_var = NULL;
738                 while (vars) {
739                     out_len = 0;
740                     sprint_realloc_objid(&buf, &buf_len, &out_len, 1,
741                                          vars->name, vars->name_length);
742                     if (vars->type == SNMP_ENDOFMIBVIEW ||
743                         memcmp(vars->name, name,
744                                rootlen * sizeof(oid)) != 0) {
745                         if (localdebug) {
746                             printf("%s => end of table\n",
747                                    buf ? (char *) buf : "[NIL]");
748                         }
749                         running = 0;
750                         break;
751                     }
752                     if (localdebug) {
753                         printf("%s => taken\n",
754                                buf ? (char *) buf : "[NIL]");
755                     }
756                     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
757                                               NETSNMP_DS_LIB_EXTENDED_INDEX)) {
758                         name_p = strchr(buf, '[');
759                     } else {
760                         switch (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
761                                                   NETSNMP_DS_LIB_OID_OUTPUT_FORMAT)) {
762                         case NETSNMP_OID_OUTPUT_MODULE:
763                         case 0:
764                             name_p = strrchr(buf, ':');
765                             break;
766                         case NETSNMP_OID_OUTPUT_SUFFIX:
767                             name_p = buf;
768                             break;
769                         case NETSNMP_OID_OUTPUT_FULL:
770                         case NETSNMP_OID_OUTPUT_NUMERIC:
771                         case NETSNMP_OID_OUTPUT_UCD:
772                             name_p = buf + strlen(table_name)+1;
773                             name_p = strchr(name_p, '.')+1;
774                             break;
775                         default:
776                             fprintf(stderr, "Unrecognized -O option: %d\n",
777                                     netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
778                                                       NETSNMP_DS_LIB_OID_OUTPUT_FORMAT));
779                             exit(1);
780                         }
781                         name_p = strchr(name_p, '.') + 1;
782                     }
783                     for (row = 0; row < entries; row++)
784                         if (strcmp(name_p, indices[row]) == 0)
785                             break;
786                     if (row == entries) {
787                         entries++;
788                         if (entries >= allocated) {
789                             if (allocated == 0) {
790                                 allocated = 10;
791                                 data =
792                                     (char **) malloc(allocated * fields *
793                                                      sizeof(char *));
794                                 memset(data, 0,
795                                        allocated * fields *
796                                        sizeof(char *));
797                                 indices =
798                                     (char **) malloc(allocated *
799                                                      sizeof(char *));
800                             } else {
801                                 allocated += 10;
802                                 data =
803                                     (char **) realloc(data,
804                                                       allocated * fields *
805                                                       sizeof(char *));
806                                 memset(data + entries * fields, 0,
807                                        (allocated -
808                                         entries) * fields *
809                                        sizeof(char *));
810                                 indices =
811                                     (char **) realloc(indices,
812                                                       allocated *
813                                                       sizeof(char *));
814                             }
815                         }
816                         indices[row] = strdup(name_p);
817                         i = strlen(name_p);
818                         if (i > index_width)
819                             index_width = i;
820                     }
821                     dp = data + row * fields;
822                     out_len = 0;
823                     sprint_realloc_value(&buf, &buf_len, &out_len, 1,
824                                          vars->name, vars->name_length,
825                                          vars);
826                     for (cp = buf; *cp; cp++)
827                         if (*cp == '\n')
828                             *cp = ' ';
829                     for (col = 0; col < fields; col++)
830                         if (column[col].subid == vars->name[rootlen])
831                             break;
832                     dp[col] = buf;
833                     i = out_len;
834                     buf = NULL;
835                     buf_len = 0;
836                     if (i > column[col].width)
837                         column[col].width = i;
838                     last_var = vars;
839                     vars = vars->next_variable;
840                 }
841                 if (last_var) {
842                     name_length = last_var->name_length;
843                     memcpy(name, last_var->name,
844                            name_length * sizeof(oid));
845                 }
846             } else {
847                 /*
848                  * error in response, print it 
849                  */
850                 running = 0;
851                 if (response->errstat == SNMP_ERR_NOSUCHNAME) {
852                     printf("End of MIB\n");
853                 } else {
854                     fprintf(stderr, "Error in packet.\nReason: %s\n",
855                             snmp_errstring(response->errstat));
856                     if (response->errstat == SNMP_ERR_NOSUCHNAME) {
857                         fprintf(stderr,
858                                 "The request for this object identifier failed: ");
859                         for (count = 1, vars = response->variables;
860                              vars && count != response->errindex;
861                              vars = vars->next_variable, count++)
862                             /*EMPTY*/;
863                         if (vars) {
864                             fprint_objid(stderr, vars->name,
865                                          vars->name_length);
866                         }
867                         fprintf(stderr, "\n");
868                     }
869                     exitval = 2;
870                 }
871             }
872         } else if (status == STAT_TIMEOUT) {
873             fprintf(stderr, "Timeout: No Response from %s\n",
874                     ss->peername);
875             running = 0;
876             exitval = 1;
877         } else {                /* status == STAT_ERROR */
878             snmp_sess_perror("snmptable", ss);
879             running = 0;
880             exitval = 1;
881         }
882         if (response)
883             snmp_free_pdu(response);
884     }
885 }