blob: ecdaf2428349018b389aa1f70797c6da0ea31d57 [file] [log] [blame]
#include <net-snmp/net-snmp-config.h>
#ifdef NETSNMP_CAN_USE_NLIST
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#ifdef HAVE_NLIST_H
#include <nlist.h>
#endif
#if HAVE_KVM_H
#include <kvm.h>
#endif
#include <net-snmp/agent/auto_nlist.h>
#include "autonlist.h"
#include "kernel.h"
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/ds_agent.h>
struct autonlist *nlists = 0;
static void init_nlist(struct nlist *);
long
auto_nlist_value(const char *string)
{
struct autonlist **ptr, *it = 0;
int cmp;
if (string == 0)
return 0;
ptr = &nlists;
while (*ptr != 0 && it == 0) {
cmp = strcmp((*ptr)->symbol, string);
if (cmp == 0)
it = *ptr;
else if (cmp < 0) {
ptr = &((*ptr)->left);
} else {
ptr = &((*ptr)->right);
}
}
if (*ptr == 0) {
#if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7))
static char *n_name = NULL;
#endif
*ptr = (struct autonlist *) malloc(sizeof(struct autonlist));
memset(*ptr, 0, sizeof(struct autonlist));
it = *ptr;
it->left = 0;
it->right = 0;
it->symbol = (char *) malloc(strlen(string) + 1);
strcpy(it->symbol, string);
/*
* allocate an extra byte for inclusion of a preceding '_' later
*/
it->nl[0].n_name = (char *) malloc(strlen(string) + 2);
#if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
strcpy(it->nl[0].n_name, string);
it->nl[0].n_name[strlen(string)+1] = '\0';
#elif defined(freebsd9)
sprintf(__DECONST(char*, it->nl[0].n_name), "_%s", string);
#else
if (n_name != NULL)
free(n_name);
n_name = malloc(strlen(string) + 2);
if (n_name == NULL) {
snmp_log(LOG_ERR, "nlist err: failed to allocate memory");
return (-1);
}
snprintf(n_name, strlen(string) + 2, "_%s", string);
it->nl[0].n_name = (const char*)n_name;
#endif
it->nl[1].n_name = 0;
init_nlist(it->nl);
#if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) || \
defined(netbsd1) || defined(dragonfly))
if (it->nl[0].n_type == 0) {
#if defined(freebsd9)
strcpy(__DECONST(char*, it->nl[0].n_name), string);
__DECONST(char*, it->nl[0].n_name)[strlen(string)+1] = '\0';
#else
static char *n_name2 = NULL;
if (n_name2 != NULL)
free(n_name2);
n_name2 = malloc(strlen(string) + 1);
if (n_name2 == NULL) {
snmp_log(LOG_ERR, "nlist err: failed to allocate memory");
return (-1);
}
strcpy(n_name2, string);
it->nl[0].n_name = (const char*)n_name2;
#endif
init_nlist(it->nl);
}
#endif
if (it->nl[0].n_type == 0) {
if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
snmp_log(LOG_ERR, "nlist err: neither %s nor _%s found.\n",
string, string);
}
return (-1);
} else {
DEBUGMSGTL(("auto_nlist:auto_nlist_value",
"found symbol %s at %lx.\n",
it->symbol, it->nl[0].n_value));
return (it->nl[0].n_value);
}
} else
return (it->nl[0].n_value);
}
int
auto_nlist(const char *string, char *var, size_t size)
{
long result;
int ret;
result = auto_nlist_value(string);
if (result != -1) {
if (var != NULL) {
ret = klookup(result, var, size);
if (!ret)
snmp_log(LOG_ERR,
"auto_nlist failed on %s at location %lx\n",
string, result);
return ret;
} else
return 1;
}
return 0;
}
static void
init_nlist(struct nlist nl[])
{
int ret;
#if HAVE_KVM_OPENFILES
kvm_t *kernel;
char kvm_errbuf[4096];
if ((kernel = kvm_openfiles(KERNEL_LOC, NULL, NULL, O_RDONLY, kvm_errbuf))
== NULL) {
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
return;
} else {
snmp_log_perror("kvm_openfiles");
snmp_log(LOG_ERR, "kvm_openfiles: %s\n", kvm_errbuf);
exit(1);
}
}
if ((ret = kvm_nlist(kernel, nl)) == -1) {
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
return;
} else {
snmp_log_perror("kvm_nlist");
exit(1);
}
}
kvm_close(kernel);
#else /* ! HAVE_KVM_OPENFILES */
#if (defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)) && defined(HAVE_KNLIST)
if (knlist(nl, 1, sizeof(struct nlist)) == -1) {
DEBUGMSGTL(("auto_nlist:init_nlist", "knlist failed on symbol: %s\n",
nl[0].n_name));
if (errno == EFAULT) {
nl[0].n_type = 0;
nl[0].n_value = 0;
} else {
snmp_log_perror("knlist");
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
return;
} else {
exit(1);
}
}
}
#else
if ((ret = nlist(KERNEL_LOC, nl)) == -1) {
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
return;
} else {
snmp_log_perror("nlist");
exit(1);
}
}
#endif /*aix4 */
#endif /* ! HAVE_KVM_OPENFILES */
for (ret = 0; nl[ret].n_name != NULL; ret++) {
#if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
if (nl[ret].n_type == 0 && nl[ret].n_value != 0)
nl[ret].n_type = 1;
#endif
if (nl[ret].n_type == 0) {
if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
DEBUGMSGTL(("auto_nlist:init_nlist", "nlist err: %s not found\n",
nl[ret].n_name));
}
} else {
DEBUGMSGTL(("auto_nlist:init_nlist", "nlist: %s 0x%X\n", nl[ret].n_name,
(unsigned int) nl[ret].n_value));
}
}
}
int
KNLookup(struct nlist nl[], int nl_which, char *buf, size_t s)
{
struct nlist *nlp = &nl[nl_which];
if (nlp->n_value == 0) {
snmp_log(LOG_ERR, "Accessing non-nlisted variable: %s\n",
nlp->n_name);
nlp->n_value = -1; /* only one error message ... */
return 0;
}
if (nlp->n_value == -1)
return 0;
return klookup(nlp->n_value, buf, s);
}
#ifdef TESTING
void
auto_nlist_print_tree(int indent, struct autonlist *ptr)
{
char buf[1024];
if (indent == -2) {
snmp_log(LOG_ERR, "nlist tree:\n");
auto_nlist_print_tree(12, nlists);
} else {
if (ptr == 0)
return;
sprintf(buf, "%%%ds\n", indent);
/*
* DEBUGMSGTL(("auto_nlist", "buf: %s\n",buf));
*/
DEBUGMSGTL(("auto_nlist", buf, ptr->symbol));
auto_nlist_print_tree(indent + 2, ptr->left);
auto_nlist_print_tree(indent + 2, ptr->right);
}
}
#endif
#else /* !NETSNMP_CAN_USE_NLIST */
#include <net-snmp/agent/auto_nlist.h>
int
auto_nlist_noop(void)
{
return 0;
}
#endif /* NETSNMP_CAN_USE_NLIST */