diff options
Diffstat (limited to 'snmplib/snmp_enum.c')
-rw-r--r-- | snmplib/snmp_enum.c | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/snmplib/snmp_enum.c b/snmplib/snmp_enum.c new file mode 100644 index 0000000..8a6bd38 --- /dev/null +++ b/snmplib/snmp_enum.c @@ -0,0 +1,475 @@ +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-features.h> + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <stdio.h> +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +#if HAVE_DMALLOC_H +#include <dmalloc.h> +#endif +#include <sys/types.h> + +#include <net-snmp/types.h> +#include <net-snmp/config_api.h> + +#include <net-snmp/library/snmp_enum.h> +#include <net-snmp/library/tools.h> +#include <net-snmp/library/snmp_assert.h> + +netsnmp_feature_child_of(snmp_enum_all, libnetsnmp) + +netsnmp_feature_child_of(se_find_free_value_in_slist, snmp_enum_all) +netsnmp_feature_child_of(snmp_enum_store_list, snmp_enum_all) +netsnmp_feature_child_of(snmp_enum_store_slist, snmp_enum_all) +netsnmp_feature_child_of(snmp_enum_clear, snmp_enum_all) + +struct snmp_enum_list_str { + char *name; + struct snmp_enum_list *list; + struct snmp_enum_list_str *next; +}; + +static struct snmp_enum_list ***snmp_enum_lists; +unsigned int current_maj_num; +unsigned int current_min_num; +static struct snmp_enum_list_str *sliststorage; + +static void +free_enum_list(struct snmp_enum_list *list); + +int +init_snmp_enum(const char *type) +{ + int i; + + if (NULL != snmp_enum_lists) + return SE_OK; + + snmp_enum_lists = (struct snmp_enum_list ***) + calloc(1, sizeof(struct snmp_enum_list **) * SE_MAX_IDS); + if (!snmp_enum_lists) + return SE_NOMEM; + current_maj_num = SE_MAX_IDS; + + for (i = 0; i < SE_MAX_IDS; i++) { + if (!snmp_enum_lists[i]) + snmp_enum_lists[i] = (struct snmp_enum_list **) + calloc(1, sizeof(struct snmp_enum_list *) * SE_MAX_SUBIDS); + if (!snmp_enum_lists[i]) + return SE_NOMEM; + } + current_min_num = SE_MAX_SUBIDS; + + register_config_handler(type, "enum", se_read_conf, NULL, NULL); + return SE_OK; +} + +int +se_store_in_list(struct snmp_enum_list *new_list, + unsigned int major, unsigned int minor) +{ + int ret = SE_OK; + + if (major > current_maj_num || minor > current_min_num) { + /* + * XXX: realloc + */ + return SE_NOMEM; + } + netsnmp_assert(NULL != snmp_enum_lists); + + if (snmp_enum_lists[major][minor] != NULL) + ret = SE_ALREADY_THERE; + + snmp_enum_lists[major][minor] = new_list; + + return ret; +} + +void +se_read_conf(const char *word, char *cptr) +{ + int major, minor; + int value; + char *cp, *cp2; + char e_name[BUFSIZ]; + char e_enum[ BUFSIZ]; + + if (!cptr || *cptr=='\0') + return; + + /* + * Extract the first token + * (which should be the name of the list) + */ + cp = copy_nword(cptr, e_name, sizeof(e_name)); + cp = skip_white(cp); + if (!cp || *cp=='\0') + return; + + + /* + * Add each remaining enumeration to the list, + * using the appropriate style interface + */ + if (sscanf(e_name, "%d:%d", &major, &minor) == 2) { + /* + * Numeric major/minor style + */ + while (1) { + cp = copy_nword(cp, e_enum, sizeof(e_enum)); + if (sscanf(e_enum, "%d:", &value) != 1) { + break; + } + cp2 = e_enum; + while (*(cp2++) != ':') + ; + se_add_pair(major, minor, strdup(cp2), value); + if (!cp) + break; + } + } else { + /* + * Named enumeration + */ + while (1) { + cp = copy_nword(cp, e_enum, sizeof(e_enum)); + if (sscanf(e_enum, "%d:", &value) != 1) { + break; + } + cp2 = e_enum; + while (*(cp2++) != ':') + ; + se_add_pair_to_slist(e_name, strdup(cp2), value); + if (!cp) + break; + } + } +} + +void +se_store_enum_list(struct snmp_enum_list *new_list, + const char *token, const char *type) +{ + struct snmp_enum_list *listp = new_list; + char line[2048]; + char buf[512]; + int len; + + snprintf(line, sizeof(line), "enum %s", token); + while (listp) { + snprintf(buf, sizeof(buf), " %d:%s", listp->value, listp->label); + /* + * Calculate the space left in the buffer. + * If this is not sufficient to include the next enum, + * then save the line so far, and start again. + */ + len = sizeof(line) - strlen(line); + if ((int)strlen(buf) > len) { + read_config_store(type, line); + snprintf(line, sizeof(line), "enum %s", token); + len = sizeof(line) - strlen(line); + } + + strncat(line, buf, len); + listp = listp->next; + } + + read_config_store(type, line); +} + +#ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST +void +se_store_list(unsigned int major, unsigned int minor, const char *type) +{ + char token[32]; + + snprintf(token, sizeof(token), "%d:%d", major, minor); + se_store_enum_list(se_find_list(major, minor), token, type); +} +#endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST */ + +struct snmp_enum_list * +se_find_list(unsigned int major, unsigned int minor) +{ + if (major > current_maj_num || minor > current_min_num) + return NULL; + netsnmp_assert(NULL != snmp_enum_lists); + + return snmp_enum_lists[major][minor]; +} + +int +se_find_value_in_list(struct snmp_enum_list *list, const char *label) +{ + if (!list) + return SE_DNE; /* XXX: um, no good solution here */ + while (list) { + if (strcmp(list->label, label) == 0) + return (list->value); + list = list->next; + } + + return SE_DNE; /* XXX: um, no good solution here */ +} + +int +se_find_free_value_in_list(struct snmp_enum_list *list) +{ + int max_value = 0; + if (!list) + return SE_DNE; + + for (;list; list=list->next) { + if (max_value < list->value) + max_value = list->value; + } + return max_value+1; +} + +int +se_find_value(unsigned int major, unsigned int minor, const char *label) +{ + return se_find_value_in_list(se_find_list(major, minor), label); +} + +int +se_find_free_value(unsigned int major, unsigned int minor) +{ + return se_find_free_value_in_list(se_find_list(major, minor)); +} + +char * +se_find_label_in_list(struct snmp_enum_list *list, int value) +{ + if (!list) + return NULL; + while (list) { + if (list->value == value) + return (list->label); + list = list->next; + } + return NULL; +} + +char * +se_find_label(unsigned int major, unsigned int minor, int value) +{ + return se_find_label_in_list(se_find_list(major, minor), value); +} + +int +se_add_pair_to_list(struct snmp_enum_list **list, char *label, int value) +{ + struct snmp_enum_list *lastnode = NULL, *tmp; + + if (!list) + return SE_DNE; + + tmp = *list; + while (tmp) { + if (tmp->value == value) { + free(label); + return (SE_ALREADY_THERE); + } + lastnode = tmp; + tmp = tmp->next; + } + + if (lastnode) { + lastnode->next = SNMP_MALLOC_STRUCT(snmp_enum_list); + lastnode = lastnode->next; + } else { + (*list) = SNMP_MALLOC_STRUCT(snmp_enum_list); + lastnode = (*list); + } + if (!lastnode) { + free(label); + return (SE_NOMEM); + } + lastnode->label = label; + lastnode->value = value; + lastnode->next = NULL; + return (SE_OK); +} + +int +se_add_pair(unsigned int major, unsigned int minor, char *label, int value) +{ + struct snmp_enum_list *list = se_find_list(major, minor); + int created = (list) ? 1 : 0; + int ret = se_add_pair_to_list(&list, label, value); + if (!created) + se_store_in_list(list, major, minor); + return ret; +} + +/* + * remember a list of enums based on a lookup name. + */ +static struct snmp_enum_list ** +se_find_slist_ptr(const char *listname) +{ + struct snmp_enum_list_str *sptr; + if (!listname) + return NULL; + + for (sptr = sliststorage; sptr != NULL; sptr = sptr->next) + if (sptr->name && strcmp(sptr->name, listname) == 0) + return &sptr->list; + + return NULL; +} + +struct snmp_enum_list * +se_find_slist(const char *listname) +{ + struct snmp_enum_list **ptr = se_find_slist_ptr(listname); + return ptr ? *ptr : NULL; +} + +char * +se_find_label_in_slist(const char *listname, int value) +{ + return (se_find_label_in_list(se_find_slist(listname), value)); +} + +int +se_find_value_in_slist(const char *listname, const char *label) +{ + return (se_find_value_in_list(se_find_slist(listname), label)); +} + +#ifndef NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST +int +se_find_free_value_in_slist(const char *listname) +{ + return (se_find_free_value_in_list(se_find_slist(listname))); +} +#endif /* NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST */ + +int +se_add_pair_to_slist(const char *listname, char *label, int value) +{ + struct snmp_enum_list *list = se_find_slist(listname); + int created = (list) ? 1 : 0; + int ret = se_add_pair_to_list(&list, label, value); + + if (!created) { + struct snmp_enum_list_str *sptr = + SNMP_MALLOC_STRUCT(snmp_enum_list_str); + if (!sptr) { + free_enum_list(list); + return SE_NOMEM; + } + sptr->next = sliststorage; + sptr->name = strdup(listname); + sptr->list = list; + sliststorage = sptr; + } + return ret; +} + +static void +free_enum_list(struct snmp_enum_list *list) +{ + struct snmp_enum_list *next; + + while (list) { + next = list->next; + SNMP_FREE(list->label); + SNMP_FREE(list); + list = next; + } +} + +void +clear_snmp_enum(void) +{ + struct snmp_enum_list_str *sptr = sliststorage, *next = NULL; + int i, j; + + while (sptr != NULL) { + next = sptr->next; + free_enum_list(sptr->list); + SNMP_FREE(sptr->name); + SNMP_FREE(sptr); + sptr = next; + } + sliststorage = NULL; + + if (snmp_enum_lists) { + for (i = 0; i < SE_MAX_IDS; i++) { + if (snmp_enum_lists[i]) { + for (j = 0; j < SE_MAX_SUBIDS; j++) { + if (snmp_enum_lists[i][j]) + free_enum_list(snmp_enum_lists[i][j]); + } + SNMP_FREE(snmp_enum_lists[i]); + } + } + SNMP_FREE(snmp_enum_lists); + } +} + +void +se_clear_list(struct snmp_enum_list **list) +{ + struct snmp_enum_list *this_entry, *next_entry; + + if (!list) + return; + + this_entry = *list; + while (this_entry) { + next_entry = this_entry->next; + SNMP_FREE(this_entry->label); + SNMP_FREE(this_entry); + this_entry = next_entry; + } + *list = NULL; + return; +} + +#ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST +void +se_store_slist(const char *listname, const char *type) +{ + struct snmp_enum_list *list = se_find_slist(listname); + se_store_enum_list(list, listname, type); +} + +int +se_store_slist_callback(int majorID, int minorID, + void *serverargs, void *clientargs) +{ + char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_APPTYPE); + se_store_slist((char *)clientargs, appname); + return SNMPERR_SUCCESS; +} +#endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST */ + +#ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR +void +se_clear_slist(const char *listname) +{ + se_clear_list(se_find_slist_ptr(listname)); +} + +void +se_clear_all_lists(void) +{ + struct snmp_enum_list_str *sptr = NULL; + + for (sptr = sliststorage; sptr != NULL; sptr = sptr->next) + se_clear_list(&(sptr->list)); +} +#endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR */ |