Mercurial > flash_v2
diff packages/net/snmp/lib/current/src/mib.c @ 103:95f3e12a6327 ecos-sw-2000-06-23
Merge from eCos master repository on 2000-06-23-16:41:10-BST
| author | jlarmour |
|---|---|
| date | Fri, 23 Jun 2000 17:06:31 +0000 |
| parents | |
| children | e0c0827131d1 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/net/snmp/lib/current/src/mib.c @@ -0,0 +1,2589 @@ +//========================================================================== +// +// ./lib/current/src/mib.c +// +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//####UCDSNMPCOPYRIGHTBEGIN#### +// +// ------------------------------------------- +// +// Portions of this software may have been derived from the UCD-SNMP +// project, <http://ucd-snmp.ucdavis.edu/> from the University of +// California at Davis, which was originally based on the Carnegie Mellon +// University SNMP implementation. Portions of this software are therefore +// covered by the appropriate copyright disclaimers included herein. +// +// The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2" +// ------------------------------------------- +// +//####UCDSNMPCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): hmt +// Contributors: hmt +// Date: 2000-05-30 +// Purpose: Port of UCD-SNMP distribution to eCos. +// Description: +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== +/******************************************************************** + Copyright 1989, 1991, 1992 by Carnegie Mellon University + + Derivative Work - +Copyright 1996, 1998, 1999, 2000 The Regents of the University of California + + All Rights Reserved + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appears in all copies and +that both that copyright notice and this permission notice appear in +supporting documentation, and that the name of CMU and The Regents of +the University of California not be used in advertising or publicity +pertaining to distribution of the software without specific written +permission. + +CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR +THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*********************************************************************/ +/* + * mib.c + * + * Update: 1998-07-17 <jhy@gsu.edu> + * Added print_oid_report* functions. + * + */ +/********************************************************************** + Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of CMU not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. +******************************************************************/ +#include <config.h> + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if TIME_WITH_SYS_TIME +# ifdef WIN32 +# include <sys/timeb.h> +# else +# include <sys/time.h> +# endif +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#if HAVE_DMALLOC_H +#include <dmalloc.h> +#endif + +#include "asn1.h" +#include "snmp_api.h" +#include "mib.h" +#include "snmp.h" +#include "snmp_impl.h" +#include "parse.h" +#include "int64.h" +#include "system.h" +#include "read_config.h" +#include "snmp_debug.h" +#include "default_store.h" + +static void sprint_by_type (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static int parse_subtree (struct tree *, const char *, oid *, size_t *); +static struct tree * _sprint_objid(char *buf, oid *objid, size_t objidlen); +static char *uptimeString (u_long, char *); +static void sprint_octet_string (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_opaque (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_object_identifier (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_timeticks (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_hinted_integer (char *, long, const char *, const char *); +static void sprint_integer (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_uinteger (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_gauge (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_counter (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_networkaddress (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_ipaddress (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_null (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_bitstring (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_nsapaddress (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_counter64 (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_unknowntype (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_badtype (char *, struct variable_list *, struct enum_list *, const char *, const char *); +struct tree *_get_symbol(oid *objid, size_t objidlen, struct tree *subtree, char *buf, struct index_list *in_dices, char **end_of_known); + +#ifdef OPAQUE_SPECIAL_TYPES +static void sprint_float (char *, struct variable_list *, struct enum_list *, const char *, const char *); +static void sprint_double (char *, struct variable_list *, struct enum_list *, const char *, const char *); +#endif +void print_tree_node (FILE *f, struct tree *tp); + +/* helper functions for get_module_node */ +int node_to_oid(struct tree *, oid *, size_t *); +static int _add_strings_to_oid(struct tree *, char *, + oid *, size_t *, size_t); + +extern struct tree *tree_head; + +struct tree *Mib; /* Backwards compatibility */ + +oid RFC1213_MIB[] = { 1, 3, 6, 1, 2, 1 }; +static char Standard_Prefix[] = ".1.3.6.1.2.1"; + +/* Set default here as some uses of read_objid require valid pointer. */ +static char *Prefix = &Standard_Prefix[0]; +typedef struct _PrefixList { + const char *str; + int len; +} *PrefixListPtr, PrefixList; + +/* + * Here are the prefix strings. + * Note that the first one finds the value of Prefix or Standard_Prefix. + * Any of these MAY start with period; all will NOT end with period. + * Period is added where needed. See use of Prefix in this module. + */ +PrefixList mib_prefixes[] = { + { &Standard_Prefix[0] }, /* placeholder for Prefix data */ + { ".iso.org.dod.internet.mgmt.mib-2" }, + { ".iso.org.dod.internet.experimental" }, + { ".iso.org.dod.internet.private" }, + { ".iso.org.dod.internet.snmpParties" }, + { ".iso.org.dod.internet.snmpSecrets" }, + { NULL, 0 } /* end of list */ +}; + +static char * +uptimeString(u_long timeticks, + char *buf) +{ + int centisecs, seconds, minutes, hours, days; + + centisecs = timeticks % 100; + timeticks /= 100; + days = timeticks / (60 * 60 * 24); + timeticks %= (60 * 60 * 24); + + hours = timeticks / (60 * 60); + timeticks %= (60 * 60); + + minutes = timeticks / 60; + seconds = timeticks % 60; + + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)) + sprintf(buf, "%d:%d:%02d:%02d.%02d", + days, hours, minutes, seconds, centisecs); + else { + if (days == 0){ + sprintf(buf, "%d:%02d:%02d.%02d", + hours, minutes, seconds, centisecs); + } else if (days == 1) { + sprintf(buf, "%d day, %d:%02d:%02d.%02d", + days, hours, minutes, seconds, centisecs); + } else { + sprintf(buf, "%d days, %d:%02d:%02d.%02d", + days, hours, minutes, seconds, centisecs); + } + } + return buf; +} + + + +void sprint_hexstring(char *buf, + const u_char *cp, + size_t len) +{ + + for(; len >= 16; len -= 16){ + sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X ", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + buf += strlen(buf); + cp += 8; + sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + buf += strlen(buf); + if (len > 16) { *buf++ = '\n'; *buf = 0; } + cp += 8; + } + for(; len > 0; len--){ + sprintf(buf, "%02X ", *cp++); + buf += strlen(buf); + } + *buf = '\0'; +} + +void sprint_asciistring(char *buf, + u_char *cp, + size_t len) +{ + int x; + + for(x = 0; x < (int)len; x++){ + if (isprint(*cp)){ + *buf++ = *cp++; + } else { + *buf++ = '.'; + cp++; + } +#if 0 + if ((x % 48) == 47) + *buf++ = '\n'; +#endif + } + *buf = '\0'; +} + + +/* + 0 + < 4 + hex + + 0 "" + < 4 hex Hex: oo oo oo + < 4 "fgh" Hex: oo oo oo + > 4 hex Hex: oo oo oo oo oo oo oo oo + > 4 "this is a test" + + */ + +static void +sprint_octet_string(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + int hex, x; + u_char *cp; + const char *saved_hint = hint; + char *saved_buf = buf; + + if (var->type != ASN_OCTET_STR){ + sprintf(buf, "Wrong Type (should be OCTET STRING): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + + if (hint) { + int repeat, width = 1; + long value; + char code = 'd', separ = 0, term = 0, ch; + u_char *ecp; + + *buf = 0; + cp = var->val.string; + ecp = cp + var->val_len; + while (cp < ecp) { + repeat = 1; + if (*hint) { + if (*hint == '*') { + repeat = *cp++; + hint++; + } + width = 0; + while ('0' <= *hint && *hint <= '9') + width = width * 10 + *hint++ - '0'; + code = *hint++; + if ((ch = *hint) && ch != '*' && (ch < '0' || ch > '9') + && (width != 0 || (ch != 'x' && ch != 'd' && ch != 'o'))) + separ = *hint++; + else separ = 0; + if ((ch = *hint) && ch != '*' && (ch < '0' || ch > '9') + && (width != 0 || (ch != 'x' && ch != 'd' && ch != 'o'))) + term = *hint++; + else term = 0; + if (width == 0) width = 1; + } + while (repeat && cp < ecp) { + value = 0; + if (code != 'a') + for (x = 0; x < width; x++) value = value * 256 + *cp++; + switch (code) { + case 'x': + sprintf (buf, "%lx", value); break; + case 'd': + sprintf (buf, "%ld", value); break; + case 'o': + sprintf (buf, "%lo", value); break; + case 'a': + for (x = 0; x < width && cp < ecp; x++) + *buf++ = *cp++; + *buf = 0; + break; + default: + sprintf(saved_buf, "(Bad hint ignored: %s) ", saved_hint); + sprint_octet_string(saved_buf+strlen(saved_buf), + var, enums, NULL, NULL); + return; + } + buf += strlen (buf); + if (cp < ecp && separ) *buf++ = separ; + repeat--; + } + if (term && cp < ecp) *buf++ = term; + } + if (units) sprintf (buf, " %s", units); + return; + } + + hex = 0; + for(cp = var->val.string, x = 0; x < (int)var->val_len; x++, cp++){ + if (!(isprint(*cp) || isspace(*cp))) + hex = 1; + } + if (var->val_len == 0){ + strcpy(buf, "\"\""); + return; + } + if (!hex){ + *buf++ = '"'; + sprint_asciistring(buf, var->val.string, var->val_len); + buf += strlen(buf); + *buf++ = '"'; + *buf = '\0'; + } + if (hex || ((var->val_len <= 4) && !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT))){ + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + *buf++ = '"'; + *buf = '\0'; + } else { + sprintf(buf, " Hex: "); + buf += strlen(buf); + } + sprint_hexstring(buf, var->val.string, var->val_len); + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + buf += strlen(buf); + *buf++ = '"'; + *buf = '\0'; + } + } + if (units) sprintf (buf, " %s", units); +} + +#ifdef OPAQUE_SPECIAL_TYPES + +static void +sprint_float(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_OPAQUE_FLOAT) { + sprintf(buf, "Wrong Type (should be Float): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "Opaque: Float:"); + buf += strlen(buf); + } + sprintf(buf, " %f", *var->val.floatVal); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_double(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_OPAQUE_DOUBLE) { + sprintf(buf, "Wrong Type (should be Double): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "Opaque: Double:"); + buf += strlen(buf); + } + sprintf(buf, " %f", *var->val.doubleVal); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +#endif /* OPAQUE_SPECIAL_TYPES */ + +static void +sprint_opaque(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + + if (var->type != ASN_OPAQUE +#ifdef OPAQUE_SPECIAL_TYPES + && var->type != ASN_OPAQUE_COUNTER64 + && var->type != ASN_OPAQUE_U64 + && var->type != ASN_OPAQUE_I64 + && var->type != ASN_OPAQUE_FLOAT + && var->type != ASN_OPAQUE_DOUBLE +#endif /* OPAQUE_SPECIAL_TYPES */ + ){ + sprintf(buf, "Wrong Type (should be Opaque): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } +#ifdef OPAQUE_SPECIAL_TYPES + switch(var->type) { + case ASN_OPAQUE_COUNTER64: + case ASN_OPAQUE_U64: + case ASN_OPAQUE_I64: + sprint_counter64(buf, var, enums, hint, units); + break; + + case ASN_OPAQUE_FLOAT: + sprint_float(buf, var, enums, hint, units); + break; + + case ASN_OPAQUE_DOUBLE: + sprint_double(buf, var, enums, hint, units); + break; + + case ASN_OPAQUE: +#endif + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "OPAQUE: "); + buf += strlen(buf); + } + sprint_hexstring(buf, var->val.string, var->val_len); + buf += strlen (buf); +#ifdef OPAQUE_SPECIAL_TYPES + } +#endif + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_object_identifier(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_OBJECT_ID){ + sprintf(buf, "Wrong Type (should be OBJECT IDENTIFIER): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "OID: "); + buf += strlen(buf); + } + _sprint_objid(buf, (oid *)(var->val.objid), var->val_len / sizeof(oid)); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_timeticks(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + char timebuf[32]; + + if (var->type != ASN_TIMETICKS){ + sprintf(buf, "Wrong Type (should be Timeticks): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "Timeticks: (%lu) ", *(u_long *)(var->val.integer)); + buf += strlen(buf); + } + sprintf(buf, "%s", uptimeString(*(u_long *)(var->val.integer), timebuf)); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_hinted_integer (char *buf, + long val, + const char *hint, + const char *units) +{ + char code; + int shift, len; + char tmp[256]; + char fmt[10]; + + code = hint[0]; + if (hint [1] == '-') { + shift = atoi (hint+2); + } + else shift = 0; + fmt[0] = '%'; + fmt[1] = 'l'; + fmt[2] = code; + fmt[3] = 0; + sprintf (tmp, fmt, val); + if (shift != 0) { + len = strlen (tmp); + if (shift <= len) { + tmp[len+1] = 0; + while (shift--) { + tmp[len] = tmp[len-1]; + len--; + } + tmp[len] = '.'; + } + else { + tmp[shift+1] = 0; + while (shift) { + if (len-- > 0) tmp [shift] = tmp [len]; + else tmp[shift] = '0'; + shift--; + } + tmp[0] = '.'; + } + } + strcpy (buf, tmp); +} + +static void +sprint_integer(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + char *enum_string = NULL; + + if (var->type != ASN_INTEGER){ + sprintf(buf, "Wrong Type (should be INTEGER): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + for (; enums; enums = enums->next) + if (enums->value == *var->val.integer){ + enum_string = enums->label; + break; + } + if (enum_string == NULL || + ds_get_boolean(DS_LIBRARY_ID,DS_LIB_PRINT_NUMERIC_ENUM)) { + if (hint) sprint_hinted_integer(buf, *var->val.integer, hint, units); + else sprintf(buf, "%ld", *var->val.integer); + } + else if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)) + sprintf(buf, "%s", enum_string); + else + sprintf(buf, "%s(%ld)", enum_string, *var->val.integer); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_uinteger(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + char *enum_string = NULL; + + if (var->type != ASN_UINTEGER){ + sprintf(buf, "Wrong Type (should be UInteger32): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + for (; enums; enums = enums->next) + if (enums->value == *var->val.integer){ + enum_string = enums->label; + break; + } + if (enum_string == NULL || + ds_get_boolean(DS_LIBRARY_ID,DS_LIB_PRINT_NUMERIC_ENUM)) + sprintf(buf, "%lu", *var->val.integer); + else if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)) + sprintf(buf, "%s", enum_string); + else + sprintf(buf, "%s(%lu)", enum_string, *var->val.integer); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_gauge(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_GAUGE){ + sprintf(buf, "Wrong Type (should be Gauge): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)) + sprintf(buf, "%lu", *var->val.integer); + else + sprintf(buf, "Gauge: %lu", *var->val.integer); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_counter(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_COUNTER){ + sprintf(buf, "Wrong Type (should be Counter): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + sprintf(buf, "%lu", *var->val.integer); + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_networkaddress(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + int x, len; + u_char *cp; + + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "Network Address: "); + buf += strlen(buf); + } + cp = var->val.string; + len = var->val_len; + for(x = 0; x < len; x++){ + sprintf(buf, "%02X", *cp++); + buf += strlen(buf); + if (x < (len - 1)) + *buf++ = ':'; + } +} + +static void +sprint_ipaddress(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + u_char *ip; + + if (var->type != ASN_IPADDRESS){ + sprintf(buf, "Wrong Type (should be Ipaddress): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + ip = var->val.string; + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)) + sprintf(buf, "%d.%d.%d.%d",ip[0], ip[1], ip[2], ip[3]); + else + sprintf(buf, "IpAddress: %d.%d.%d.%d",ip[0], ip[1], ip[2], ip[3]); +} + +static void +sprint_null(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_NULL){ + sprintf(buf, "Wrong Type (should be NULL): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + sprintf(buf, "NULL"); +} + +static void +sprint_bitstring(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + int len, bit; + u_char *cp; + char *enum_string; + + if (var->type != ASN_BIT_STR && var->type != ASN_OCTET_STR){ + sprintf(buf, "Wrong Type (should be BIT STRING): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + *buf++ = '"'; + *buf = '\0'; + } else { + sprintf(buf, "BITS: "); + buf += strlen(buf); + } + sprint_hexstring(buf, var->val.bitstring, var->val_len); + buf += strlen(buf); + + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + buf += strlen(buf); + *buf++ = '"'; + *buf = '\0'; + } else { + cp = var->val.bitstring; + for(len = 0; len < (int)var->val_len; len++){ + for(bit = 0; bit < 8; bit++){ + if (*cp & (0x80 >> bit)){ + enum_string = NULL; + for (; enums; enums = enums->next) + if (enums->value == (len * 8) + bit){ + enum_string = enums->label; + break; + } + if (enum_string == NULL || + ds_get_boolean(DS_LIBRARY_ID,DS_LIB_PRINT_NUMERIC_ENUM)) + sprintf(buf, "%d ", (len * 8) + bit); + else + sprintf(buf, "%s(%d) ", enum_string, (len * 8) + bit); + buf += strlen(buf); + } + } + cp ++; + } + } +} + +static void +sprint_nsapaddress(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + if (var->type != ASN_NSAP){ + sprintf(buf, "Wrong Type (should be NsapAddress): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ + sprintf(buf, "NsapAddress: "); + buf += strlen(buf); + } + sprint_hexstring(buf, var->val.string, var->val_len); +} + +static void +sprint_counter64(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + char a64buf[I64CHARSZ+1]; + + if (var->type != ASN_COUNTER64 +#ifdef OPAQUE_SPECIAL_TYPES + && var->type != ASN_OPAQUE_COUNTER64 + && var->type != ASN_OPAQUE_I64 + && var->type != ASN_OPAQUE_U64 +#endif + ){ + sprintf(buf, "Wrong Type (should be Counter64): "); + buf += strlen(buf); + sprint_by_type(buf, var, NULL, NULL, NULL); + return; + } + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)){ +#ifdef OPAQUE_SPECIAL_TYPES + if (var->type != ASN_COUNTER64) { + sprintf(buf, "Opaque: "); + buf += strlen(buf); + } +#endif +#ifdef OPAQUE_SPECIAL_TYPES + switch(var->type) { + case ASN_OPAQUE_U64: + sprintf(buf, "UInt64: "); + break; + case ASN_OPAQUE_I64: + sprintf(buf, "Int64: "); + break; + case ASN_COUNTER64: + case ASN_OPAQUE_COUNTER64: +#endif + sprintf(buf, "Counter64: "); +#ifdef OPAQUE_SPECIAL_TYPES + } +#endif + buf += strlen(buf); + } +#ifdef OPAQUE_SPECIAL_TYPES + if (var->type == ASN_OPAQUE_I64) + { + printI64(a64buf, var->val.counter64); + sprintf(buf, a64buf); + } + else +#endif + { + printU64(a64buf, var->val.counter64); + sprintf(buf, a64buf); + } + buf += strlen (buf); + if (units) sprintf (buf, " %s", units); +} + +static void +sprint_unknowntype(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ +/* sprintf(buf, "Variable has bad type"); */ + sprint_by_type(buf, var, NULL, NULL, NULL); +} + +static void +sprint_badtype(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + sprintf(buf, "Variable has bad type"); +} + +static void +sprint_by_type(char *buf, + struct variable_list *var, + struct enum_list *enums, + const char *hint, + const char *units) +{ + switch (var->type){ + case ASN_INTEGER: + sprint_integer(buf, var, enums, hint, units); + break; + case ASN_OCTET_STR: + sprint_octet_string(buf, var, enums, hint, units); + break; + case ASN_BIT_STR: + sprint_bitstring(buf, var, enums, hint, units); + break; + case ASN_OPAQUE: + sprint_opaque(buf, var, enums, hint, units); + break; + case ASN_OBJECT_ID: + sprint_object_identifier(buf, var, enums, hint, units); + break; + case ASN_TIMETICKS: + sprint_timeticks(buf, var, enums, hint, units); + break; + case ASN_GAUGE: + sprint_gauge(buf, var, enums, hint, units); + break; + case ASN_COUNTER: + sprint_counter(buf, var, enums, hint, units); + break; + case ASN_IPADDRESS: + sprint_ipaddress(buf, var, enums, hint, units); + break; + case ASN_NULL: + sprint_null(buf, var, enums, hint, units); + break; + case ASN_UINTEGER: + sprint_uinteger(buf, var, enums, hint, units); + break; + case ASN_COUNTER64: +#ifdef OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_U64: + case ASN_OPAQUE_I64: + case ASN_OPAQUE_COUNTER64: +#endif /* OPAQUE_SPECIAL_TYPES */ + sprint_counter64(buf, var, enums, hint, units); + break; +#ifdef OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_FLOAT: + sprint_float(buf, var, enums, hint, units); + break; + case ASN_OPAQUE_DOUBLE: + sprint_double(buf, var, enums, hint, units); + break; +#endif /* OPAQUE_SPECIAL_TYPES */ + default: + DEBUGMSGTL(("sprint_by_type", "bad type: %d\n", var->type)); + sprint_badtype(buf, var, enums, hint, units); + break; + } +} + + +struct tree *get_tree_head(void) +{ + return(tree_head); +} + +static char *confmibdir=NULL; +static char *confmibs=NULL; + +void +handle_mibdirs_conf(const char *token, + char *line) +{ + char *ctmp; + + if (confmibdir) { + ctmp = (char *)malloc(strlen(confmibdir) + strlen(line) + 1); + if (*line == '+') + line++; + sprintf(ctmp,"%s%c%s",confmibdir, ENV_SEPARATOR_CHAR, line); + free(confmibdir); + confmibdir = ctmp; + } else { + confmibdir=strdup(line); + } + DEBUGMSGTL(("read_config:initmib", "using mibdirs: %s\n", confmibdir)); +} + +void +handle_mibs_conf(const char *token, + char *line) +{ + char *ctmp; + + if (confmibs) { + ctmp = (char *)malloc(strlen(confmibs) + strlen(line) + 1); + if (*line == '+') + line++; + sprintf(ctmp,"%s%c%s",confmibs, ENV_SEPARATOR_CHAR, line); + free(confmibs); + confmibs = ctmp; + } else { + confmibs=strdup(line); + } + DEBUGMSGTL(("read_config:initmib", "using mibs: %s\n", confmibs)); +} + +void +handle_mibfile_conf(const char *token, + char *line) +{ + DEBUGMSGTL(("read_config:initmib", "reading mibfile: %s\n", line)); + read_mib(line); +} + +char * +snmp_out_toggle_options(char *options) +{ + while(*options) { + switch(*options++) { + case 'n': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_OIDS); + break; + case 'e': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_ENUM); + break; + case 'b': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_DONT_BREAKDOWN_OIDS); + break; + case 'q': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT); + break; + case 'f': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID); + break; + case 's': + snmp_set_suffix_only(1); + break; + case 'S': + snmp_set_suffix_only(2); + break; + default: + return options-1; + } + } + return NULL; +} + +void snmp_out_toggle_options_usage(const char *lead, FILE *outf) +{ + fprintf(outf, "%sOUTOPTS values:\n", lead); + fprintf(outf, "%s n: Print oids numerically.\n", lead); + fprintf(outf, "%s e: Print enums numerically.\n", lead); + fprintf(outf, "%s b: Dont break oid indexes down.\n", lead); + fprintf(outf, "%s q: Quick print for easier parsing.\n", lead); + fprintf(outf, "%s f: Print full oids on output.\n", lead); + fprintf(outf, "%s s: Print only last symbolic element of oid.\n", lead); + fprintf(outf, "%s S: Print MIB module-id plus last element.\n", lead); +} + +char * +snmp_in_toggle_options(char *options) +{ + while(*options) { + switch(*options++) { + case 'R': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_RANDOM_ACCESS); + break; + case 'b': + ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_REGEX_ACCESS); + break; + default: + return options-1; + } + } + return NULL; +} + +void snmp_in_toggle_options_usage(const char *lead, FILE *outf) +{ + fprintf(outf, "%sINOPTS values:\n", lead); + fprintf(outf, "%s R: Do random access to oid labels.\n", lead); + fprintf(outf, "%s b: Do best/regex matching to find a MIB node.\n", lead); +} + +void +register_mib_handlers (void) +{ + register_premib_handler("snmp","mibdirs", + handle_mibdirs_conf, NULL, + "[mib-dirs|+mib-dirs]"); + register_premib_handler("snmp","mibs", + handle_mibs_conf,NULL, + "[mib-tokens|+mib-tokens]"); + register_config_handler("snmp","mibfile", + handle_mibfile_conf, NULL, + "mibfile-to-read"); + + /* register the snmp.conf configuration handlers for default + parsing behaviour */ + + ds_register_premib(ASN_BOOLEAN, "snmp","showMibErrors", + DS_LIBRARY_ID, DS_LIB_MIB_ERRORS); + ds_register_premib(ASN_BOOLEAN, "snmp","strictCommentTerm", + DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM); + ds_register_premib(ASN_BOOLEAN, "snmp","mibAllowUnderline", + DS_LIBRARY_ID, DS_LIB_MIB_PARSE_LABEL); + ds_register_premib(ASN_INTEGER, "snmp","mibWarningLevel", + DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS); + ds_register_premib(ASN_BOOLEAN, "snmp","mibReplaceWithLatest", + DS_LIBRARY_ID, DS_LIB_MIB_REPLACE); + + ds_register_config(ASN_BOOLEAN, "snmp","printNumericEnums", + DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_ENUM); + ds_register_config(ASN_BOOLEAN, "snmp","printNumericOids", + DS_LIBRARY_ID, DS_LIB_PRINT_NUMERIC_OIDS); + ds_register_config(ASN_BOOLEAN, "snmp","dontBreakdownOids", + DS_LIBRARY_ID, DS_LIB_DONT_BREAKDOWN_OIDS); + ds_register_config(ASN_BOOLEAN, "snmp","quickPrinting", + DS_LIBRARY_ID, DS_LIB_QUICK_PRINT); + ds_register_config(ASN_INTEGER, "snmp","suffixPrinting", + DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY); + + /* setup the default parser configurations, as specified by configure */ +#ifdef MIB_COMMENT_IS_EOL_TERMINATED + ds_set_boolean(DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM, 1); +#else /* !MIB_COMMENT_IS_EOL_TERMINATED */ + ds_set_boolean(DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM, 0); +#endif /* !MIB_COMMENT_IS_EOL_TERMINATED */ +} + +void +init_mib (void) +{ + const char *prefix; + char *env_var, *entry; + PrefixListPtr pp = &mib_prefixes[0]; + char *new_mibdirs, *homepath, *cp_home; + + if (Mib) return; + + /* Initialise the MIB directory/ies */ + + /* we can't use the environment variable directly, because strtok + will modify it. */ + + env_var = getenv("MIBDIRS"); + if ( env_var == NULL ) { + if (confmibdir != NULL) + env_var = strdup(confmibdir); + else + env_var = strdup(DEFAULT_MIBDIRS); + } else { + env_var = strdup(env_var); + } + if (*env_var == '+') { + entry = (char *)malloc(strlen(DEFAULT_MIBDIRS)+strlen(env_var)+2); + sprintf(entry, "%s%c%s", DEFAULT_MIBDIRS, ENV_SEPARATOR_CHAR, env_var+1); + free(env_var); + env_var = entry; + } + + /* replace $HOME in the path with the users home directory */ + homepath=getenv("HOME"); + + if (homepath) { + while((cp_home = strstr(env_var, "$HOME"))) { + new_mibdirs = (char *) malloc(strlen(env_var) - strlen("$HOME") + + strlen(homepath)+1); + *cp_home = 0; /* null out the spot where we stop copying */ + sprintf(new_mibdirs, "%s%s%s", env_var, homepath, + cp_home + strlen("$HOME")); + /* swap in the new value and repeat */ + free(env_var); + env_var = new_mibdirs; + } + } + + DEBUGMSGTL(("init_mib","Seen MIBDIRS: Looking in '%s' for mib dirs ...\n",env_var)); + + entry = strtok( env_var, ENV_SEPARATOR ); + while ( entry ) { + add_mibdir(entry); + entry = strtok( NULL, ENV_SEPARATOR); + } + free(env_var); + + init_mib_internals(); + + /* Read in any modules or mibs requested */ + + env_var = getenv("MIBS"); + if ( env_var == NULL ) { + if (confmibs != NULL) + env_var = strdup(confmibs); + else + env_var = strdup(DEFAULT_MIBS); + } else { + env_var = strdup(env_var); + } + if (*env_var == '+') { + entry = (char *)malloc(strlen(DEFAULT_MIBS)+strlen(env_var)+2); + sprintf(entry, "%s%c%s", DEFAULT_MIBS, ENV_SEPARATOR_CHAR, env_var+1); + free(env_var); + env_var = entry; + } + + DEBUGMSGTL(("init_mib","Seen MIBS: Looking in '%s' for mib files ...\n",env_var)); + entry = strtok( env_var, ENV_SEPARATOR ); + while ( entry ) { + if (strcasecmp(entry, DEBUG_ALWAYS_TOKEN) == 0) { + read_all_mibs(); + } + else if (strstr (entry, "/") != 0) { + read_mib(entry); + } + else { + read_module(entry); + } + entry = strtok( NULL, ENV_SEPARATOR); + } + adopt_orphans(); + free(env_var); + + env_var = getenv("MIBFILES"); + if ( env_var != NULL ) { + if (*env_var == '+') { +#ifdef DEFAULT_MIBFILES + entry = (char *)malloc(strlen(DEFAULT_MIBFILES)+strlen(env_var)+2); + sprintf(entry, "%s%c%s", DEFAULT_MIBFILES, ENV_SEPARATOR_CHAR, + env_var+1); + free(env_var); + env_var = entry; +#else + env_var = strdup(env_var+1); +#endif + } else { + env_var = strdup(env_var); + } + } else { +#ifdef DEFAULT_MIBFILES + env_var = strdup(DEFAULT_MIBFILES); +#endif + } + + if ( env_var != 0 ) { + DEBUGMSGTL(("init_mib","Seen MIBFILES: Looking in '%s' for mib files ...\n",env_var)); + entry = strtok( env_var, ENV_SEPARATOR ); + while ( entry ) { + read_mib(entry); + entry = strtok( NULL, ENV_SEPARATOR); + } + free(env_var); + } + + prefix = getenv("PREFIX"); + + if (!prefix) + prefix = Standard_Prefix; + + Prefix = (char*)malloc(strlen(prefix)+2); + strcpy(Prefix, prefix); + + DEBUGMSGTL(("init_mib","Seen PREFIX: Looking in '%s' for prefix ...\n", Prefix)); + + /* remove trailing dot */ + env_var = &Prefix[strlen(Prefix) - 1]; + if (*env_var == '.') *env_var = '\0'; + + pp->str = Prefix; /* fixup first mib_prefix entry */ + /* now that the list of prefixes is built, save each string length. */ + while (pp->str) { + pp->len = strlen(pp->str); + pp++; + } + + if (getenv("SUFFIX")) + ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY, 1); + + Mib = tree_head; /* Backwards compatibility */ +} + +void +print_mib (FILE *fp) +{ + print_subtree (fp, tree_head, 0); +} + +void +print_ascii_dump (FILE *fp) +{ + fprintf(fp, "dump DEFINITIONS ::= BEGIN\n"); + print_ascii_dump_tree (fp, tree_head, 0); + fprintf(fp, "END\n"); +} + +void +set_function(struct tree *subtree) +{ + switch(subtree->type){ + case TYPE_OBJID: + subtree->printer = sprint_object_identifier; + break; + case TYPE_OCTETSTR: + subtree->printer = sprint_octet_string; + break; + case TYPE_INTEGER: + subtree->printer = sprint_integer; + break; + case TYPE_NETADDR: + subtree->printer = sprint_networkaddress; + break; + case TYPE_IPADDR: + subtree->printer = sprint_ipaddress; + break; + case TYPE_COUNTER: + subtree->printer = sprint_counter; + break; + case TYPE_GAUGE: + subtree->printer = sprint_gauge; + break; + case TYPE_TIMETICKS: + subtree->printer = sprint_timeticks; + break; + case TYPE_OPAQUE: + subtree->printer = sprint_opaque; + break; + case TYPE_NULL: + subtree->printer = sprint_null; + break; + case TYPE_BITSTRING: + subtree->printer = sprint_bitstring; + break; + case TYPE_NSAPADDRESS: + subtree->printer = sprint_nsapaddress; + break; + case TYPE_COUNTER64: + subtree->printer = sprint_counter64; + break; + case TYPE_UINTEGER: + subtree->printer = sprint_uinteger; + break; + case TYPE_OTHER: + default: + subtree->printer = sprint_unknowntype; + break; + } +} + +/* + * Read an object identifier from input string into internal OID form. + * Returns 1 if successful. + * If an error occurs, this function returns 0 and MAY set snmp_errno. + * snmp_errno is NOT set if SET_SNMP_ERROR evaluates to nothing. + * This can make multi-threaded use a tiny bit more robust. + */ +int read_objid(const char *input, + oid *output, + size_t *out_len) /* number of subid's in "output" */ +{ + struct tree *root = tree_head; + char buf[SPRINT_MAX_LEN]; + int ret; + + if (strchr(input, ':')) { + return get_node(input, output, out_len); + } + + if (*input == '.') + input++; + else { + /* get past leading '.', append '.' to Prefix. */ + if (*Prefix == '.') + strcpy(buf, Prefix+1); + else + strcpy(buf, Prefix); + strcat(buf, "."); + strcat(buf, input); + input = buf; + } + + if (root == NULL){ + SET_SNMP_ERROR(SNMPERR_NOMIB); + *out_len = 0; + return(0); + } + if ((ret = parse_subtree(root, input, output, out_len)) <= 0) + { + int errc = (ret ? ret : SNMPERR_UNKNOWN_OBJID); + SET_SNMP_ERROR(errc); + return (0); + } + *out_len = ret; + + return (1); +} + + +/* + * RECURSIVE helper methods for read_objid + * Returns: + * < 0 the SNMPERR_ errorcode + * = 0 input string is empty. + * > 0 the number of sub-identifiers found in the input string. + */ +static int +parse_subtree(struct tree *subtree, + const char *input, + oid *output, + size_t *out_len) /* number of subid's */ +{ + char buf[SPRINT_MAX_LEN], *to = buf, *cp; + u_long subid = 0; + struct tree *tp; + int ret, len; + + /* + * No empty strings. Can happen if there is a trailing '.' or two '.'s + * in a row, i.e. "..". + */ + if ((*input == '\0') || + (*input == '.')) + return (0); + + if (*input == '"' || *input == '\'') { + /* + * This is a string that should be converted into an OID + * Note: assumes variable length index is required, and prepends + * the string length. + */ + if ((cp = strchr(input+1, *input)) == NULL) { + /* error. Should be a matching quote somewhere. */ + return (0); + } + + /* is there room enough for the string in question plus its length */ + len = cp-input-1; + if ((int)*out_len <= len){ + return (SNMPERR_LONG_OID); + } + + /* copy everything in */ + if (*input++ == '"') { + /* add the length for " quoted objects */ + *output++ = len++; + } + + *out_len -= len; + while (input < cp) { + *output++ = *input++; + } + + /* Now, we assume that nothing beyond this exists in the parse + tree, which should always be true (or else we have a really wacked + mib designer somewhere. */ + input = cp + 1; /* past the quote */ + + if (*input != '.') + return (len); + + ret = parse_subtree(NULL, ++input, output, out_len); + if (ret <= 0) + return (ret); + return ret+len; + + } else if (isdigit(*input)) { + /* + * Read the number, then try to find it in the subtree. + */ + while (isdigit(*input)) { + *to++ = *input; + subid *= 10; + subid += *input++ - '0'; + } + if (*input != '.' && *input != 0) { + while (*input != 0 && *input != '.') *to++ = *input++; + *to = 0; + snmp_set_detail(buf); + return SNMPERR_BAD_SUBID; + } + *to = '\0'; + + for (tp = subtree; tp; tp = tp->next_peer) { + if (tp->subid == subid) + goto found; + } + } + else { + /* + * Read the name into a buffer. + */ + while ((*input != '\0') && + (*input != '.')) { + *to++ = *input++; + } + *to = '\0'; + + /* + * Find the name in the subtree; + */ + for (tp = subtree; tp; tp = tp->next_peer) { + if (strcasecmp(tp->label, buf) == 0) { + subid = tp->subid; + goto found; + } + } + + /* + * If we didn't find the entry, punt... + */ + if (tp == NULL) { + snmp_set_detail(buf); + return (SNMPERR_BAD_SUBID); + } + } + +found: + if(subid > (u_long)MAX_SUBID){ + snmp_set_detail(buf); + return (SNMPERR_MAX_SUBID); + } + + if ((int)*out_len <= 0){ + return (SNMPERR_LONG_OID); + } + + (*out_len)--; + *output++ = subid; + + if (*input != '.') + return (1); + + ret = parse_subtree(tp ? tp->child_list : NULL, + ++input, output, out_len); + if (ret <= 0) + return (ret); + return ret+1; +} + +static struct tree * +_sprint_objid(char *buf, + oid *objid, + size_t objidlen) /* number of subidentifiers */ +{ + char tempbuf[SPRINT_MAX_LEN], *cp; + struct tree *subtree = tree_head; + char *midpoint = 0; + + *tempbuf = '.'; /* this is a fully qualified name */ + subtree = _get_symbol(objid, objidlen, subtree, tempbuf + 1, 0, &midpoint); + if (ds_get_boolean(DS_LIBRARY_ID,DS_LIB_PRINT_NUMERIC_OIDS)) { + cp = tempbuf; + } else if (ds_get_int(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY)){ + for(cp = tempbuf; *cp; cp++) + ; + if (midpoint) + cp = midpoint-2; /* beyond the '.' */ + else { + while(cp >= tempbuf){ + if (isalpha(*cp)) + break; + cp--; + } + } + while(cp >= tempbuf){ + if (*cp == '.') + break; + cp--; + } + cp++; + if (ds_get_int(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY) == 2 && cp > tempbuf) { + char modbuf[256]; + char *mod = module_name(subtree->modid, modbuf); + size_t len = strlen(mod); + if ((int)len+1 >= cp-tempbuf) { + memmove(tempbuf+len+2, cp, strlen(cp)+1); + cp = tempbuf+len+2; + } + cp -= len+2; + memcpy(cp, mod, len); + cp[len] = ':'; + cp[len+1] = ':'; + } + } + else if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID)) { + PrefixListPtr pp = &mib_prefixes[0]; + int ii; + size_t ilen, tlen; + const char *testcp; + cp = tempbuf; tlen = strlen(tempbuf); + ii = 0; + while (pp->str) { + ilen = pp->len; testcp = pp->str; + if ((tlen > ilen) && !memcmp(tempbuf, testcp, ilen)) { + cp += (ilen + 1); + break; + } + pp++; + } + } + else cp = tempbuf; + strcpy(buf, cp); + return subtree; +} + +char * sprint_objid(char *buf, oid *objid, size_t objidlen) +{ + _sprint_objid(buf,objid,objidlen); + return buf; +} + +void +print_objid(oid *objid, + size_t objidlen) /* number of subidentifiers */ +{ + fprint_objid(stdout, objid, objidlen); +} + +void +fprint_objid(FILE *f, + oid *objid, + size_t objidlen) /* number of subidentifiers */ +{ + char buf[SPRINT_MAX_LEN]; + + _sprint_objid(buf, objid, objidlen); + fprintf(f, "%s\n", buf); +} + +void +sprint_variable(char *buf, + oid *objid, + size_t objidlen, + struct variable_list *variable) +{ + struct tree *subtree; + + subtree = _sprint_objid(buf, objid, objidlen); + buf += strlen(buf); + if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT)) + strcat(buf, " "); + else + strcat(buf, " = "); + buf += strlen(buf); + + if (variable->type == SNMP_NOSUCHOBJECT) + strcpy(buf, "No Such Object available on this agent"); + else if (variable->type == SNMP_NOSUCHINSTANCE) + strcpy(buf, "No Such Instance currently exists"); + else if (variable->type == SNMP_ENDOFMIBVIEW) + strcpy(buf, "No more variables left in this MIB View"); + else if (subtree) { + if (subtree->printer) + (*subtree->printer)(buf, variable, subtree->enums, subtree->hint, subtree->units); + else { + sprint_by_type(buf, variable, subtree->enums, subtree->hint, subtree->units); + } + } + else { /* handle rare case where tree is empty */ + sprint_by_type(buf, variable, 0, 0, 0); + } +} + +void +print_variable(oid *objid, + size_t objidlen, + struct variable_list *variable) +{ + fprint_variable(stdout, objid, objidlen, variable); +} + +void +fprint_variable(FILE *f, + oid *objid, + size_t objidlen, + struct variable_list *variable) +{ + char buf[SPRINT_MAX_LEN]; + + sprint_variable(buf, objid, objidlen, variable); + fprintf(f, "%s\n", buf); +} + +void +sprint_value(char *buf, + oid *objid, + size_t objidlen, + struct variable_list *variable) +{ + char tempbuf[SPRINT_MAX_LEN]; + struct tree *subtree = tree_head; + + if (variable->type == SNMP_NOSUCHOBJECT) + sprintf(buf, "No Such Object available on this agent"); + else if (variable->type == SNMP_NOSUCHINSTANCE) + sprintf(buf, "No Such Instance currently exists"); + else if (variable->type == SNMP_ENDOFMIBVIEW) + sprintf(buf, "No more variables left in this MIB View"); + else { + subtree = get_symbol(objid, objidlen, subtree, tempbuf); + if (subtree->printer) + (*subtree->printer)(buf, variable, subtree->enums, subtree->hint, subtree->units); + else { + sprint_by_type(buf, variable, subtree->enums, subtree->hint, subtree->units); + } + } +} + +void +print_value(oid *objid, + size_t objidlen, + struct variable_list *variable) +{ + fprint_value(stdout, objid, objidlen, variable); +} + +void +fprint_value(FILE *f, + oid *objid, + size_t objidlen, + struct variable_list *variable) +{ + char tempbuf[SPRINT_MAX_LEN]; + + sprint_value(tempbuf, objid, objidlen, variable); + fprintf(f, "%s\n", tempbuf); +} + + +/* + * Append a quoted printable string to buffer "buf" + * that represents a range of sub-identifiers "objid". + * + * Display '.' for all non-printable sub-identifiers. + * If successful, "buf" points past the appended string. + */ +char * +dump_oid_to_string(oid *objid, + size_t objidlen, + char *buf, + char quotechar) +{ + if (buf) + { int ii, alen; + char *scp; + char *cp = buf + (strlen(buf)); + scp = cp; + for (ii= 0, alen = 0; ii < (int)objidlen; ii++) + { + oid tst = objid[ii]; + if ((tst > 254) || (!isprint(tst))) + tst = (oid)'.'; + + if (alen == 0) *cp++ = quotechar; + *cp++ = (char)tst; + alen++; + } + if (alen) *cp++ = quotechar; + *cp = '\0'; + buf = cp; + } + + return buf; +} + +struct tree * +_get_symbol(oid *objid, + size_t objidlen, + struct tree *subtree, + char *buf, + struct index_list *in_dices, + char **end_of_known) +{ + struct tree *return_tree = NULL; + + if (!objid || !buf) + return NULL; + + for(; subtree; subtree = subtree->next_peer){ + if (*objid == subtree->subid){ + if (subtree->indexes) + in_dices = subtree->indexes; + if (!strncmp( subtree->label, ANON, ANON_LEN) || + ds_get_boolean(DS_LIBRARY_ID,DS_LIB_PRINT_NUMERIC_OIDS)) + sprintf(buf, "%lu", subtree->subid); + else + strcpy(buf, subtree->label); + goto found; + } + } + + if (end_of_known) + *end_of_known = buf; + + /* subtree not found */ + + while (in_dices && (objidlen > 0) && + !ds_get_boolean(DS_LIBRARY_ID,DS_LIB_PRINT_NUMERIC_OIDS) && + !ds_get_boolean(DS_LIBRARY_ID,DS_LIB_DONT_BREAKDOWN_OIDS)) { + size_t numids; + struct tree *tp; + tp = find_tree_node(in_dices->ilabel, -1); + if (0 == tp) { + /* ack. Can't find an index in the mib tree. bail */ + goto finish_it; + } + switch(tp->type) { + case TYPE_OCTETSTR: + if (in_dices->isimplied) { + numids = objidlen; + buf = dump_oid_to_string(objid, numids, buf, '\''); + } else { + numids = (size_t)*objid+1; + if (numids > objidlen) + goto finish_it; + if (numids == 1) { + *buf++ = '"'; *buf++ = '"'; + } + else + buf = dump_oid_to_string(objid+1, numids-1, buf, '"'); + } + objid += (numids); + objidlen -= (numids); + *buf++ = '.'; + *buf = '\0'; + break; + case TYPE_INTEGER: + sprintf(buf, "%lu.", *objid++); + while(*buf) + buf++; + objidlen--; + break; + case TYPE_OBJID: + if (in_dices->isimplied) { + numids = objidlen; + } else { + numids = (size_t)*objid+1; + } + if ( numids > objidlen) + goto finish_it; + _get_symbol(objid, numids, NULL, buf, NULL, NULL); + objid += (numids); + objidlen -= (numids); + buf += strlen(buf); + *buf++ = '.'; + *buf = '\0'; + break; + default: + goto finish_it; + break; + } + in_dices = in_dices->next; + } + +finish_it: + + while(objidlen-- > 0){ /* output rest of name, uninterpreted */ + sprintf(buf, "%lu.", *objid++); + while(*buf) + buf++; + } + *(buf - 1) = '\0'; /* remove trailing dot */ + return NULL; + +found: + if (objidlen > 1){ + while(*buf) + buf++; + *buf++ = '.'; + *buf = '\0'; + + return_tree = _get_symbol(objid + 1, objidlen - 1, subtree->child_list, + buf, in_dices, end_of_known); + } + if (return_tree != NULL) + return return_tree; + else + return subtree; +} + +struct tree * +get_symbol(oid *objid, + size_t objidlen, + struct tree *subtree, + char *buf) +{ + return _get_symbol(objid,objidlen,subtree,buf,0,0); +} + +/* + * Clone of get_symbol that doesn't take a buffer argument + */ +struct tree * +get_tree(oid *objid, + size_t objidlen, + struct tree *subtree) +{ + struct tree *return_tree = NULL; + + for(; subtree; subtree = subtree->next_peer){ + if (*objid == subtree->subid) + goto found; + } + + return NULL; + +found: + if (objidlen > 1) + return_tree = get_tree(objid + 1, objidlen - 1, subtree->child_list); + if (return_tree != NULL) + return return_tree; + else + return subtree; +} + +void +print_description(oid *objid, + size_t objidlen) /* number of subidentifiers */ +{ + fprint_description(stdout, objid, objidlen); +} + +void +fprint_description(FILE *f, + oid *objid, + size_t objidlen) /* number of subidentifiers */ +{ + struct tree *tp = get_tree(objid, objidlen, tree_head); + struct tree *subtree = tree_head; + fprintf(f, "%s OBJECT-TYPE\n", tp->label); + print_tree_node(f, tp); + fprintf(f, "::= {"); + while (objidlen > 1) { + for(; subtree; subtree = subtree->next_peer){ + if (*objid == subtree->subid){ + if (strncmp( subtree->label, ANON, ANON_LEN)) + fprintf(f, " %s(%lu)", subtree->label, subtree->subid); + else + fprintf(f, " %lu", subtree->subid); + break; + } + } + if (subtree == 0) break; + objid++; objidlen--; subtree = subtree->child_list; + if (subtree == 0) break; + } + fprintf(f, " %lu }\n", *objid); +} + +void +print_tree_node(FILE *f, + struct tree *tp) +{ + const char *cp; + char str[MAXTOKEN]; + int i, prevmod; + if (tp) { + module_name(tp->modid, str); + fprintf(f, " -- FROM\t%s", str); + for (i = 1, prevmod = tp->modid; i < tp->number_modules; i++) { + if (prevmod != tp->module_list[i]) { + module_name(tp->module_list[i], str); + fprintf(f, ", %s", str); + } + prevmod = tp->module_list[i]; + } + fprintf(f, "\n"); + if (tp->tc_index != -1) { + fprintf(f, " -- TEXTUAL CONVENTION %s\n", get_tc_descriptor(tp->tc_index)); + } + switch (tp->type) { + case TYPE_OBJID: cp = "OBJECT IDENTIFIER"; break; + case TYPE_OCTETSTR: cp = "OCTET STRING"; break; + case TYPE_INTEGER: cp = "INTEGER"; break; + case TYPE_NETADDR: cp = "NetworkAddress"; break; + case TYPE_IPADDR: cp = "IpAddress"; break; + case TYPE_COUNTER: cp = "Counter"; break; + case TYPE_GAUGE: cp = "Gauge"; break; + case TYPE_TIMETICKS: cp = "TimeTicks"; break; + case TYPE_OPAQUE: cp = "Opaque"; break; + case TYPE_NULL: cp = "NULL"; break; + case TYPE_COUNTER64: cp = "Counter64"; break; + case TYPE_BITSTRING: cp = "BIT STRING"; break; + case TYPE_NSAPADDRESS: cp = "NsapAddress"; break; + case TYPE_UINTEGER: cp = "UInteger32"; break; + case 0: cp = NULL; break; + default: sprintf(str,"type_%d", tp->type); cp = str; + } +#if SNMP_TESTING_CODE + if (!cp && (tp->ranges || tp->enums)) { /* ranges without type ? */ + sprintf(str,"?0 with %s %s ?", + tp->ranges ? "Range" : "", + tp->enums ? "Enum" : ""); + cp = str; + } +#endif /* SNMP_TESTING_CODE */ + if (cp) fprintf(f, " SYNTAX\t%s", cp); + if (tp->ranges) { + struct range_list *rp = tp->ranges; + int first = 1; + fprintf(f, " ("); + while (rp) { + if (first) first = 0; + else fprintf(f, " | "); + if (rp->low == rp->high) fprintf(f, "%d", rp->low); + else fprintf(f, "%d..%d", rp->low, rp->high); + rp = rp->next; + } + fprintf(f, ") "); + } + if (tp->enums) { + struct enum_list *ep = tp->enums; + int first = 1; + fprintf(f," { "); + while (ep) { + if (first) first = 0; + else fprintf(f, ", "); + fprintf(f, "%s(%d)", ep->label, ep->value); + ep = ep->next; + } + fprintf(f," } "); + } + if (cp) fprintf(f, "\n"); + if (tp->hint) fprintf(f, " DISPLAY-HINT\t\"%s\"\n", tp->hint); + if (tp->units) fprintf(f, " UNITS\t\"%s\"\n", tp->units); + switch (tp->access) { + case MIB_ACCESS_READONLY: cp = "read-only"; break; + case MIB_ACCESS_READWRITE: cp = "read-write"; break; + case MIB_ACCESS_WRITEONLY: cp = "write-only"; break; + case MIB_ACCESS_NOACCESS: cp = "not-accessible"; break; + case MIB_ACCESS_NOTIFY: cp = "accessible-for-notify"; break; + case MIB_ACCESS_CREATE: cp = "read-create"; break; + case 0: cp = NULL; break; + default: sprintf(str,"access_%d", tp->access); cp = str; + } + if (cp) fprintf(f, " MAX-ACCESS\t%s\n", cp); + switch (tp->status) { + case MIB_STATUS_MANDATORY: cp = "mandatory"; break; + case MIB_STATUS_OPTIONAL: cp = "optional"; break; + case MIB_STATUS_OBSOLETE: cp = "obsolete"; break; + case MIB_STATUS_DEPRECATED: cp = "deprecated"; break; + case MIB_STATUS_CURRENT: cp = "current"; break; + case 0: cp = NULL; break; + default: sprintf(str,"status_%d", tp->status); cp = str; + } +#if SNMP_TESTING_CODE + if (!cp && (tp->indexes)) { /* index without status ? */ + sprintf(str,"?0 with %s ?", + tp->indexes ? "Index" : ""); + cp = str; + } +#endif /* SNMP_TESTING_CODE */ + if (cp) fprintf(f, " STATUS\t%s\n", cp); + if (tp->indexes) { + struct index_list *ip = tp->indexes; + int first=1; + fprintf(f, " INDEXES\t"); + fprintf(f," { "); + while (ip) { + if (first) first = 0; + else fprintf(f, ", "); + if (ip->isimplied) + fprintf(f, "IMPLIED "); + fprintf(f, "%s", ip->ilabel); + ip = ip->next; + } + fprintf(f," }\n"); + } + if (tp->description) fprintf(f, " DESCRIPTION\t\"%s\"\n", tp->description); + } + else + fprintf(f, "No description\n"); +} + +int +get_module_node(const char *fname, + const char *module, + oid *objid, + size_t *objidlen) +{ + int modid, rc = 0; + struct tree *tp; + char *name, *cp; + + if ( !strcmp(module, "ANY") ) + modid = -1; + else { + read_module(module); + modid = which_module( module ); + if (modid == -1) return 0; + } + + /* Isolate the first component of the name ... */ + name = strdup(fname); + cp = strchr( name, '.' ); + if ( cp != NULL ) { + *cp = '\0'; + cp++; + } + /* ... and locate it in the tree. */ + tp = find_tree_node(name, modid); + if (tp){ + size_t maxlen = *objidlen; + + /* Set the first element of the object ID */ + if (node_to_oid(tp, objid, objidlen)) { + rc = 1; + + /* If the name requested was more than one element, + tag on the rest of the components */ + if (cp != NULL) + rc = _add_strings_to_oid(tp, cp, objid, objidlen, maxlen); + } + } + + free(name); + return (rc); +} + + +/* + * Populate object identifier from a node in the MIB hierarchy. + * Build up the object ID, working backwards, + * starting from the end of the objid buffer. + * When the top of the MIB tree is reached, adjust the buffer. + * + * The buffer length is set to the number of subidentifiers + * for the object identifier associated with the MIB node. + * Returns the number of subidentifiers copied. + * + * If 0 is returned, the objid buffer is too small, + * and the buffer contents are indeterminate. + * The buffer length can be used to create a larger buffer. + */ +int +node_to_oid(struct tree *tp, oid *objid, size_t *objidlen) +{ + int numids, lenids; + oid *op; + + if (!tp || !objid || !objidlen) + return 0; + + lenids = (int)*objidlen; + op = objid + lenids; /* points after the last element */ + + for(numids = 0; tp; tp = tp->parent, numids++) + { + if (numids >= lenids) continue; + --op; + *op = tp->subid; + } + + *objidlen = (size_t)numids; + if (numids > lenids) { + return 0; + } + + if (numids < lenids) + memmove(objid, op, numids * sizeof(oid)); + + return (numids); +} + +static int +_add_strings_to_oid(struct tree *tp, char *cp, + oid *objid, size_t *objidlen, + size_t maxlen) +{ + int subid; + struct tree *tp2 = NULL; + char *cp2 = NULL; + char doingquote = 0; + + while ( cp != NULL ) { + cp2 = strchr( cp, '.' ); /* Isolate the next entry */ + if ( cp2 != NULL ) { + *cp2 = '\0'; + cp2++; + } + + if ( *cp == '"' || *cp == '\'') { /* Is it the beggining + of a quoted string */ + doingquote = *cp++; + /* insert length if requested */ + if (doingquote == '"') { + if (*objidlen >= maxlen) + return 0; + objid[ *objidlen ] = (strchr(cp,doingquote) - cp); + (*objidlen)++; + } + + while(*cp != doingquote) { + if (*objidlen >= maxlen) + return 0; + objid[ *objidlen ] = *cp++; + (*objidlen)++; + } + + tp = NULL; /* must be pure numeric from here, right? */ + cp = cp2; + continue; + } + + /* Is it numeric ? */ + if ( isdigit( *cp ) ) + subid=(strtol(cp,0,0)); + else + subid = -1; + + /* Search for the appropriate child */ + if ( tp != NULL ) + tp2 = tp->child_list; + while ( tp2 != NULL ) { + if (( (int)tp2->subid == subid ) || + ( !strcasecmp( tp2->label, cp ))) { + if (*objidlen >= maxlen) + return 0; + objid[ *objidlen ] = tp2->subid; + (*objidlen)++; + tp = tp2; + break; + } + tp2 = tp2->next_peer; + } + if ( tp2 == NULL ) { + if ( subid == -1 ) { + return 0; + } + /* pure numeric from now on */ + if (*objidlen >= maxlen) + return 0; + objid[ *objidlen ] = subid; + (*objidlen)++; + tp = NULL; + } + cp = cp2; + } + + return 1; +} + + +/* + * see comments on find_best_tree_node for usage after first time. + */ +int +get_wild_node(const char *name, + oid *objid, + size_t *objidlen) +{ + struct tree *tp = find_best_tree_node(name, tree_head, NULL); + if (!tp) + return 0; + return get_node(tp->label, objid, objidlen); +} + +int +get_node(const char *name, + oid *objid, + size_t *objidlen) +{ + char *cp; + int res; + + if (( cp=strchr(name, ':')) == NULL ) + res = get_module_node( name, "ANY", objid, objidlen ); + else { + char *module; + /* + * requested name is of the form + * "module:subidentifier" + */ + module = (char *)malloc((size_t)(cp-name+1)); + memcpy(module,name,(size_t)(cp-name)); + module[cp-name] = 0; + cp++; /* cp now point to the subidentifier */ + if (*cp == ':') cp++; + + /* 'cp' and 'name' *do* go that way round! */ + res = get_module_node( cp, module, objid, objidlen ); + free(module); + } + if (res == 0) { + SET_SNMP_ERROR(SNMPERR_UNKNOWN_OBJID); + } + + return res; +} + +#ifdef testing + +main(int argc, char* argv[]) +{ + oid objid[MAX_OID_LEN]; + int objidlen = MAX_OID_LEN; + int count; + struct variable_list variable; + + init_mib(); + if (argc < 2) + print_subtree(stdout, tree_head, 0); + variable.type = ASN_INTEGER; + variable.val.integer = 3; + variable.val_len = 4; + for (argc--; argc; argc--, argv++) { + objidlen = MAX_OID_LEN; + printf("read_objid(%s) = %d\n", + argv[1], read_objid(argv[1], objid, &objidlen)); + for(count = 0; count < objidlen; count++) + printf("%d.", objid[count]); + printf("\n"); + print_variable(objid, objidlen, &variable); + } +} + +#endif /* testing */ + +/* initialize: no peers included in the report. */ +void clear_tree_flags(register struct tree *tp) +{ + for (; tp; tp = tp->next_peer) + { + tp->reported = 0; + if (tp->child_list) + clear_tree_flags(tp->child_list); /*RECURSE*/ + } +} + +/* + * Update: 1998-07-17 <jhy@gsu.edu> + * Added print_oid_report* functions. + */ +static int print_subtree_oid_report_labeledoid = 0; +static int print_subtree_oid_report_oid = 0; +static int print_subtree_oid_report_symbolic = 0; +static int print_subtree_oid_report_suffix = 0; + +/* These methods recurse. */ +static void print_parent_labeledoid(FILE *, struct tree *); +static void print_parent_oid(FILE *, struct tree *); +static void print_parent_label(FILE *, struct tree *); +static void print_subtree_oid_report(FILE *, struct tree *, int); + + +void +print_oid_report (FILE *fp) +{ + struct tree *tp; + clear_tree_flags(tree_head); + for (tp = tree_head ; tp ; tp=tp->next_peer) + print_subtree_oid_report (fp, tp, 0); +} + +void +print_oid_report_enable_labeledoid (void) +{ + print_subtree_oid_report_labeledoid = 1; +} + +void +print_oid_report_enable_oid (void) +{ + print_subtree_oid_report_oid = 1; +} + +void +print_oid_report_enable_suffix (void) +{ + print_subtree_oid_report_suffix = 1; +} + +void +print_oid_report_enable_symbolic (void) +{ + print_subtree_oid_report_symbolic = 1; +} + +/* + * helper methods for print_subtree_oid_report() + * each one traverses back up the node tree + * until there is no parent. Then, the label combination + * is output, such that the parent is displayed first. + * + * Warning: these methods are all recursive. + */ + +static void +print_parent_labeledoid(FILE *f, + struct tree *tp) +{ + if(tp) + { + if(tp->parent) + { + print_parent_labeledoid(f, tp->parent); /*RECURSE*/ + } + fprintf(f, ".%s(%lu)", tp->label, tp->subid); + } +} + +static void +print_parent_oid(FILE *f, + struct tree *tp) +{ + if(tp) + { + if(tp->parent) + { + print_parent_oid(f, tp->parent); /*RECURSE*/ + } + fprintf(f, ".%lu", tp->subid); + } +} + +static void +print_parent_label(FILE *f, + struct tree *tp) +{ + if(tp) + { + if(tp->parent) + { + print_parent_label(f, tp->parent); /*RECURSE*/ + } + fprintf(f, ".%s", tp->label); + } +} + +/* + * print_subtree_oid_report(): + * + * This methods generates variations on the original print_subtree() report. + * Traverse the tree depth first, from least to greatest sub-identifier. + * Warning: this methods recurses and calls methods that recurse. + */ + +static void +print_subtree_oid_report(FILE *f, + struct tree *tree, + int count) +{ + struct tree *tp; + + count++; + + /* sanity check */ + if(!tree) + { + return; + } + + /* + * find the not reported peer with the lowest sub-identifier. + * if no more, break the loop and cleanup. + * set "reported" flag, and create report for this peer. + * recurse using the children of this peer, if any. + */ + while (1) + { + register struct tree *ntp; + + tp = 0; + for (ntp = tree->child_list; ntp; ntp = ntp->next_peer) + { + if (ntp->reported) continue; + + if (!tp || (tp->subid > ntp->subid)) + tp = ntp; + } + if (!tp) break; + + tp->reported = 1; + + if(print_subtree_oid_report_labeledoid) + { + print_parent_labeledoid(f, tp); + fprintf(f, "\n"); + } + if(print_subtree_oid_report_oid) + { + print_parent_oid(f, tp); + fprintf(f, "\n"); + } + if(print_subtree_oid_report_symbolic) + { + print_parent_label(f, tp); + fprintf(f, "\n"); + } + if(print_subtree_oid_report_suffix) + { + int i; + for(i = 0; i < count; i++) + fprintf(f, " "); + fprintf(f, "%s(%ld) type=%d", tp->label, tp->subid, tp->type); + if (tp->tc_index != -1) fprintf(f, " tc=%d", tp->tc_index); + if (tp->hint) fprintf(f, " hint=%s", tp->hint); + if (tp->units) fprintf(f, " units=%s", tp->units); + + fprintf(f, "\n"); + } + print_subtree_oid_report(f, tp, count); /*RECURSE*/ + } +} + + +/* + * Convert timeticks to hours, minutes, seconds string. + * CMU compatible does not show centiseconds. + */ +char *uptime_string(u_long timeticks, char *buf) +{ + char tbuf[64]; + char * cp; + uptimeString(timeticks, tbuf); + cp = strrchr(tbuf, '.'); +#ifdef CMU_COMPATIBLE + if (cp) *cp = '\0'; +#endif + strcpy(buf, tbuf); + return buf; +} + +#ifdef CMU_COMPATIBLE + +int mib_TxtToOid(char *Buf, oid **OidP, size_t *LenP) +{ + return read_objid(Buf, *OidP, LenP); +} + +int mib_OidToTxt(oid *O, size_t OidLen, char *Buf, size_t BufLen) +{ + _sprint_objid(Buf, O, OidLen); + return 1; +} + +#endif /* CMU_COMPATIBLE */
