blob: 8a6bd384673bd1b9c60610eefc4dd2c1990efd11 [file] [log] [blame]
#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 */