summaryrefslogtreecommitdiff
path: root/snmplib/snmp_enum.c
diff options
context:
space:
mode:
Diffstat (limited to 'snmplib/snmp_enum.c')
-rw-r--r--snmplib/snmp_enum.c475
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 */