#include #include #if HAVE_STDLIB_H #include #endif #if HAVE_STRING_H #include #else #include #endif #include #if HAVE_NETINET_IN_H #include #endif #if HAVE_STDARG_H #include #else #include #endif #if HAVE_WINSOCK_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_DMALLOC_H #include #endif #include #include #include /* For this file's "internal" definitions */ #include #include #include #include #define SNMP_DEBUG_DISABLED 0 #define SNMP_DEBUG_ACTIVE 1 #define SNMP_DEBUG_EXCLUDED 2 static int dodebug = SNMP_ALWAYS_DEBUG; int debug_num_tokens = 0; int debug_num_excluded = 0; static int debug_print_everything = 0; netsnmp_token_descr dbg_tokens[MAX_DEBUG_TOKENS]; #ifdef NETSNMP_DEBUG_STATS netsnmp_container *dbg_stats = NULL; static int _debug_cmp( const void *lhs, const void *rhs ); static int _save_debug_stat(netsnmp_token_descr *tb, void *type); static int _debug_stats_callback(int majorID, int minorID, void *serverarg, void *clientarg); #endif /* * indent debugging: provide a space padded section to return an indent for */ static int debugindent = 0; #define INDENTMAX 80 static char debugindentchars[] = " "; /* * Prototype definitions */ void debug_config_register_tokens(const char *configtoken, char *tokens); void debug_config_turn_on_debugging(const char *configtoken, char *line); char * debug_indent(void) { return debugindentchars; } void debug_indent_add(int amount) { if (debugindent + amount >= 0 && debugindent + amount < 80) { debugindentchars[debugindent] = ' '; debugindent += amount; debugindentchars[debugindent] = '\0'; } } void debug_config_register_tokens(const char *configtoken, char *tokens) { debug_register_tokens(tokens); } void debug_config_turn_on_debugging(const char *configtoken, char *line) { snmp_set_do_debugging(atoi(line)); } void snmp_debug_init(void) { debugindentchars[0] = '\0'; /* zero out the debugging indent array. */ /* * Hmmm.... * this "init" routine seems to be called *after* processing * the command line options. So we can't clear the debug * token array here, and will just have to rely on it being * initialised to 0 automatically. * So much for trying to program responsibly :-) */ /* memset(dbg_tokens, 0, MAX_DEBUG_TOKENS*sizeof(struct token_dscr)); */ register_prenetsnmp_mib_handler("snmp", "doDebugging", debug_config_turn_on_debugging, NULL, "(1|0)"); register_prenetsnmp_mib_handler("snmp", "debugTokens", debug_config_register_tokens, NULL, "token[,token...]"); #ifdef NETSNMP_DEBUG_STATS /* * debug stats */ dbg_stats = netsnmp_container_find("debug_exclude:table_container"); if (NULL != dbg_stats) { dbg_stats->compare = _debug_cmp; netsnmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, _debug_stats_callback, dbg_stats, 1024); } #endif } void debug_register_tokens(char *tokens) { char *newp, *cp; char *st; int status; if (tokens == 0 || *tokens == 0) return; newp = strdup(tokens); /* strtok_r messes it up */ cp = strtok_r(newp, DEBUG_TOKEN_DELIMITER, &st); while (cp) { if (strlen(cp) < MAX_DEBUG_TOKEN_LEN) { if (strcasecmp(cp, DEBUG_ALWAYS_TOKEN) == 0) { debug_print_everything = 1; } else if (debug_num_tokens < MAX_DEBUG_TOKENS) { if ('-' == *cp) { ++cp; status = SNMP_DEBUG_EXCLUDED; } else status = SNMP_DEBUG_ACTIVE; dbg_tokens[debug_num_tokens].token_name = strdup(cp); dbg_tokens[debug_num_tokens++].enabled = status; snmp_log(LOG_NOTICE, "registered debug token %s, %d\n", cp, status); } else { snmp_log(LOG_NOTICE, "Unable to register debug token %s\n", cp); } } else { snmp_log(LOG_NOTICE, "Debug token %s over length\n", cp); } cp = strtok_r(NULL, DEBUG_TOKEN_DELIMITER, &st); } free(newp); } /* * Print all registered tokens along with their current status */ void debug_print_registered_tokens(void) { int i; snmp_log(LOG_INFO, "%d tokens registered :\n", debug_num_tokens); for (i=0; itoken_name = strdup(token); netsnmp_assert(0 == found->enabled); CONTAINER_INSERT(dbg_stats, found); } ++found->enabled; /* snmp_log(LOG_ERR,"tok %s, %d hits\n", token, found->enabled); */ } #endif return rc; } void #if HAVE_STDARG_H debugmsg(const char *token, const char *format, ...) #else debugmsg(va_alist) va_dcl #endif { va_list debugargs; #if HAVE_STDARG_H va_start(debugargs, format); #else const char *format; const char *token; va_start(debugargs); token = va_arg(debugargs, const char *); format = va_arg(debugargs, const char *); /* ??? */ #endif if (debug_is_token_registered(token) == SNMPERR_SUCCESS) { snmp_vlog(LOG_DEBUG, format, debugargs); } va_end(debugargs); } void debugmsg_oid(const char *token, const oid * theoid, size_t len) { u_char *buf = NULL; size_t buf_len = 0, out_len = 0; if (sprint_realloc_objid(&buf, &buf_len, &out_len, 1, theoid, len)) { if (buf != NULL) { debugmsg(token, "%s", buf); } } else { if (buf != NULL) { debugmsg(token, "%s [TRUNCATED]", buf); } } if (buf != NULL) { free(buf); } } void debugmsg_suboid(const char *token, const oid * theoid, size_t len) { u_char *buf = NULL; size_t buf_len = 0, out_len = 0; int buf_overflow = 0; netsnmp_sprint_realloc_objid(&buf, &buf_len, &out_len, 1, &buf_overflow, theoid, len); if(buf_overflow) { if (buf != NULL) { debugmsg(token, "%s [TRUNCATED]", buf); } } else { if (buf != NULL) { debugmsg(token, "%s", buf); } } if (buf != NULL) { free(buf); } } void debugmsg_var(const char *token, netsnmp_variable_list * var) { u_char *buf = NULL; size_t buf_len = 0, out_len = 0; if (var == NULL || token == NULL) { return; } if (sprint_realloc_variable(&buf, &buf_len, &out_len, 1, var->name, var->name_length, var)) { if (buf != NULL) { debugmsg(token, "%s", buf); } } else { if (buf != NULL) { debugmsg(token, "%s [TRUNCATED]", buf); } } if (buf != NULL) { free(buf); } } void debugmsg_oidrange(const char *token, const oid * theoid, size_t len, size_t var_subid, oid range_ubound) { u_char *buf = NULL; size_t buf_len = 0, out_len = 0, i = 0; int rc = 0; if (var_subid == 0) { rc = sprint_realloc_objid(&buf, &buf_len, &out_len, 1, theoid, len); } else { char tmpbuf[128]; /* XXX - ? check for 0 == var_subid -1 ? */ rc = sprint_realloc_objid(&buf, &buf_len, &out_len, 1, theoid, var_subid-1); /* Adjust for C's 0-based array indexing */ if (rc) { sprintf(tmpbuf, ".%lu--%lu", theoid[var_subid - 1], range_ubound); rc = snmp_strcat(&buf, &buf_len, &out_len, 1, tmpbuf); if (rc) { for (i = var_subid; i < len; i++) { sprintf(tmpbuf, ".%lu", theoid[i]); if (!snmp_strcat(&buf, &buf_len, &out_len, 1, tmpbuf)) { break; } } } } } if (buf != NULL) { debugmsg(token, "%s%s", buf, rc ? "" : " [TRUNCATED]"); free(buf); } } void debugmsg_hex(const char *token, u_char * thedata, size_t len) { u_char *buf = NULL; size_t buf_len = 0, out_len = 0; if (sprint_realloc_hexstring (&buf, &buf_len, &out_len, 1, thedata, len)) { if (buf != NULL) { debugmsg(token, "%s", buf); } } else { if (buf != NULL) { debugmsg(token, "%s [TRUNCATED]", buf); } } if (buf != NULL) { free(buf); } } void debugmsg_hextli(const char *token, u_char * thedata, size_t len) { char buf[SPRINT_MAX_LEN], token2[SPRINT_MAX_LEN]; u_char *b3 = NULL; size_t b3_len = 0, o3_len = 0; int incr; sprintf(token2, "dumpx_%s", token); /* * XX tracing lines removed from this function DEBUGTRACE; */ DEBUGIF(token2) { for (incr = 16; len > 0; len -= incr, thedata += incr) { if ((int) len < incr) { incr = len; } /* * XXnext two lines were DEBUGPRINTINDENT(token); */ sprintf(buf, "dumpx%s", token); debugmsg(buf, "%s: %s", token2, debug_indent()); if (sprint_realloc_hexstring (&b3, &b3_len, &o3_len, 1, thedata, incr)) { if (b3 != NULL) { debugmsg(token2, "%s", b3); } } else { if (b3 != NULL) { debugmsg(token2, "%s [TRUNCATED]", b3); } } o3_len = 0; } } if (b3 != NULL) { free(b3); } } void #if HAVE_STDARG_H debugmsgtoken(const char *token, const char *format, ...) #else debugmsgtoken(va_alist) va_dcl #endif { va_list debugargs; #if HAVE_STDARG_H va_start(debugargs, format); #else const char *token; va_start(debugargs); token = va_arg(debugargs, const char *); #endif debugmsg(token, "%s: ", token); va_end(debugargs); } void #if HAVE_STDARG_H debug_combo_nc(const char *token, const char *format, ...) #else debug_combo_nc(va_alist) va_dcl #endif { va_list debugargs; #if HAVE_STDARG_H va_start(debugargs, format); #else const char *format; const char *token; va_start(debugargs); token = va_arg(debugargs, const char *); format = va_arg(debugargs, const char *); /* ??? */ #endif snmp_log(LOG_DEBUG, "%s: ", token); snmp_vlog(LOG_DEBUG, format, debugargs); va_end(debugargs); } /* * for speed, these shouldn't be in default_storage space */ void snmp_set_do_debugging(int val) { dodebug = val; } int snmp_get_do_debugging(void) { return dodebug; } #ifdef NETSNMP_DEBUG_STATS /************************************************************ * compare two context pointers here. Return -1 if lhs < rhs, * 0 if lhs == rhs, and 1 if lhs > rhs. */ static int _debug_cmp( const void *lhs, const void *rhs ) { netsnmp_token_descr *dbg_l = (netsnmp_token_descr *)lhs; netsnmp_token_descr *dbg_r = (netsnmp_token_descr *)rhs; /* snmp_log(LOG_ERR,"%s/%s\n",dbg_l->token_name, dbg_r->token_name); */ return strcmp(dbg_l->token_name, dbg_r->token_name); } static int _save_debug_stat(netsnmp_token_descr *tb, void *type) { char buf[256]; snprintf(buf, sizeof(buf), "debug_hits %s %d", tb->token_name, tb->enabled); read_config_store((char *) type, buf); return SNMP_ERR_NOERROR; } static int _debug_stats_callback(int majorID, int minorID, void *serverarg, void *clientarg) { char sep[] = "##############################################################"; char buf[] = "#\n" "# debug stats\n" "#"; char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); read_config_store((char *) type, sep); read_config_store((char *) type, buf); /* * save all rows */ CONTAINER_FOR_EACH((netsnmp_container *) clientarg, (netsnmp_container_obj_func *) _save_debug_stat, type); read_config_store((char *) type, sep); read_config_store((char *) type, "\n"); /* * never fails */ return SNMPERR_SUCCESS; } #endif