diff options
Diffstat (limited to 'agent/auto_nlist.c')
-rw-r--r-- | agent/auto_nlist.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/agent/auto_nlist.c b/agent/auto_nlist.c new file mode 100644 index 0000000..fdc5d71 --- /dev/null +++ b/agent/auto_nlist.c @@ -0,0 +1,240 @@ +#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) { + *ptr = (struct autonlist *) malloc(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) + strcpy(it->nl[0].n_name, string); + it->nl[0].n_name[strlen(string)+1] = '\0'; +#else + sprintf(it->nl[0].n_name, "_%s", string); +#endif + it->nl[1].n_name = 0; + init_nlist(it->nl); +#if !(defined(aix4) || defined(aix5) || defined(aix6)) + if (it->nl[0].n_type == 0) { + strcpy(it->nl[0].n_name, string); + it->nl[0].n_name[strlen(string)+1] = '\0'; + 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 %x.\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, int 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[]) +{ +#ifdef NETSNMP_CAN_USE_NLIST + 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(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) + 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)); + } + } +#endif /* NETSNMP_CAN_USE_NLIST */ +} + +int +KNLookup(struct nlist nl[], int nl_which, char *buf, int 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 */ |