diff options
Diffstat (limited to 'agent/mibgroup/ucd-snmp/loadave.c')
-rw-r--r-- | agent/mibgroup/ucd-snmp/loadave.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/loadave.c b/agent/mibgroup/ucd-snmp/loadave.c new file mode 100644 index 0000000..6efc5e9 --- /dev/null +++ b/agent/mibgroup/ucd-snmp/loadave.c @@ -0,0 +1,496 @@ +#include <net-snmp/net-snmp-config.h> + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <signal.h> +#if HAVE_MACHINE_PARAM_H +#include <machine/param.h> +#endif +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#if HAVE_SYS_VMMETER_H +#if !(defined(bsdi2) || defined(netbsd1)) +#include <sys/vmmeter.h> +#endif +#endif +#if HAVE_SYS_CONF_H +#include <sys/conf.h> +#endif +#if HAVE_ASM_PAGE_H +#include <asm/page.h> +#endif +#if HAVE_SYS_SWAP_H +#include <sys/swap.h> +#endif +#if HAVE_SYS_FS_H +#include <sys/fs.h> +#else +#if HAVE_UFS_FS_H +#include <ufs/fs.h> +#else +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if !defined(dragonfly) +#ifdef HAVE_SYS_VNODE_H +#include <sys/vnode.h> +#endif +#endif +#ifdef HAVE_UFS_UFS_QUOTA_H +#include <ufs/ufs/quota.h> +#endif +#ifdef HAVE_UFS_UFS_INODE_H +#include <ufs/ufs/inode.h> +#endif +#if HAVE_UFS_FFS_FS_H +#include <ufs/ffs/fs.h> +#endif +#endif +#endif +#if HAVE_MTAB_H +#include <mtab.h> +#endif +#include <errno.h> +#if HAVE_FSTAB_H +#include <fstab.h> +#endif +#if HAVE_SYS_STATFS_H +#include <sys/statfs.h> +#endif +#if HAVE_SYS_STATVFS_H +#include <sys/statvfs.h> +#endif +#if HAVE_SYS_VFS_H +#include <sys/vfs.h> +#endif +#if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS) +#if HAVE_SYS_MOUNT_H +#include <sys/mount.h> +#endif +#if HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#define statvfs statfs +#endif +#if HAVE_VM_VM_H +#include <vm/vm.h> +#endif +#if HAVE_VM_SWAP_PAGER_H +#include <vm/swap_pager.h> +#endif +#if HAVE_SYS_FIXPOINT_H +#include <sys/fixpoint.h> +#endif +#if HAVE_SYS_LOADAVG_H +#include <sys/loadavg.h> +#endif +#if HAVE_MALLOC_H +#include <malloc.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#ifdef dynix +#include <sys/mc_vmparam.h> +#endif +#if defined(hpux10) || defined(hpux11) +#include <sys/pstat.h> +#endif +#if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) +#ifdef HAVE_SYS_PROTOSW_H +#include <sys/protosw.h> +#endif +#include <libperfstat.h> +#endif +#if HAVE_SYS_SYSGET_H +#include <sys/sysget.h> +#endif + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> +#include <net-snmp/agent/auto_nlist.h> + +#include "struct.h" +#include "loadave.h" +#include "util_funcs/header_simple_table.h" +#include "kernel.h" + +static double maxload[3]; +static int laConfigSet = 0; + +static int +loadave_store_config(int a, int b, void *c, void *d) +{ + char line[SNMP_MAXBUF_SMALL]; + if (laConfigSet > 0) { + snprintf(line, SNMP_MAXBUF_SMALL, "pload %.02f %.02f %.02f", maxload[0], maxload[1], maxload[2]); + snmpd_store_config(line); + } + return SNMPERR_SUCCESS; +} + +void +init_loadave(void) +{ + + /* + * define the structure we're going to ask the agent to register our + * information at + */ + struct variable2 extensible_loadave_variables[] = { + {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {MIBINDEX}}, + {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {ERRORNAME}}, + {LOADAVE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {LOADAVE}}, + {LOADMAXVAL, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, + var_extensible_loadave, 1, {LOADMAXVAL}}, + {LOADAVEINT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {LOADAVEINT}}, +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + {LOADAVEFLOAT, ASN_OPAQUE_FLOAT, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {LOADAVEFLOAT}}, +#endif + {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {ERRORFLAG}}, + {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_loadave, 1, {ERRORMSG}} + }; + + /* + * Define the OID pointer to the top of the mib tree that we're + * registering underneath + */ + oid loadave_variables_oid[] = + { NETSNMP_UCDAVIS_MIB, NETSNMP_LOADAVEMIBNUM, 1 }; + + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("ucd-snmp/loadave", extensible_loadave_variables, + variable2, loadave_variables_oid); + + laConfigSet = 0; + + snmpd_register_config_handler("load", loadave_parse_config, + loadave_free_config, + "max1 [max5] [max15]"); + + snmpd_register_config_handler("pload", + loadave_parse_config, NULL, NULL); + + + /* + * we need to be called back later + */ + snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, + loadave_store_config, NULL); + +} + +void +loadave_parse_config(const char *token, char *cptr) +{ + int i; + + if (strcmp(token, "pload") == 0) { + if (laConfigSet < 0) { + snmp_log(LOG_WARNING, + "ignoring attempted override of read-only load\n"); + return; + } else { + laConfigSet++; + } + } else { + if (laConfigSet > 0) { + snmp_log(LOG_WARNING, + "ignoring attempted override of read-only load\n"); + /* + * Fall through and copy in this value. + */ + } + laConfigSet = -1; + } + + for (i = 0; i <= 2; i++) { + if (cptr != NULL) + maxload[i] = atof(cptr); + else + maxload[i] = maxload[i - 1]; + cptr = skip_not_white(cptr); + cptr = skip_white(cptr); + } +} + +void +loadave_free_config(void) +{ + int i; + + for (i = 0; i <= 2; i++) + maxload[i] = NETSNMP_DEFMAXLOADAVE; +} + +/* + * try to get load average + * Inputs: pointer to array of doubles, number of elements in array + * Returns: 0=array has values, -1=error occurred. + */ +int +try_getloadavg(double *r_ave, size_t s_ave) +{ +#if defined(HAVE_GETLOADAVG) || defined(linux) || defined(ultrix) \ + || defined(sun) || defined(__alpha) || defined(dynix) \ + || !defined(cygwin) && defined(NETSNMP_CAN_USE_NLIST) \ + && defined(LOADAVE_SYMBOL) + double *pave = r_ave; +#endif +#ifndef HAVE_GETLOADAVG +#ifdef HAVE_SYS_FIXPOINT_H + fix favenrun[3]; +#endif +#if (defined(ultrix) || defined(sun) || defined(__alpha) || defined(dynix)) + int i; +#if (defined(sun) || defined(__alpha) || defined(dynix)) + long favenrun[3]; + if (s_ave > 3) /* bounds check */ + return (-1); +#define FIX_TO_DBL(_IN) (((double) _IN)/((double) FSCALE)) +#endif +#endif +#if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) + int favenrun[3]; + perfstat_cpu_total_t cs; +#endif +#if defined(hpux10) || defined(hpux11) + struct pst_dynamic pst_buf; +#endif +#ifdef irix6 + int i, favenrun[3]; + sgt_cookie_t cookie; +#endif +#endif /* !HAVE_GETLOADAVG */ + +#ifdef HAVE_GETLOADAVG + if (getloadavg(pave, s_ave) == -1) + return (-1); +#elif defined(linux) + { + FILE *in = fopen("/proc/loadavg", "r"); + if (!in) { + NETSNMP_LOGONCE((LOG_ERR, "snmpd: cannot open /proc/loadavg\n")); + return (-1); + } + fscanf(in, "%lf %lf %lf", pave, (pave + 1), (pave + 2)); + fclose(in); + } +#elif (defined(ultrix) || defined(sun) || defined(__alpha) || defined(dynix)) + if (auto_nlist(LOADAVE_SYMBOL, (char *) favenrun, sizeof(favenrun)) == + 0) + return (-1); + for (i = 0; i < s_ave; i++) + *(pave + i) = FIX_TO_DBL(favenrun[i]); +#elif defined(hpux10) || defined(hpux11) + if (pstat_getdynamic(&pst_buf, sizeof(struct pst_dynamic), 1, 0) < 0) + return(-1); + r_ave[0] = pst_buf.psd_avg_1_min; + r_ave[1] = pst_buf.psd_avg_5_min; + r_ave[2] = pst_buf.psd_avg_15_min; +#elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) + if(perfstat_cpu_total((perfstat_id_t *)NULL, &cs, sizeof(perfstat_cpu_total_t), 1) > 0) { + r_ave[0] = cs.loadavg[0] / 65536.0; + r_ave[1] = cs.loadavg[1] / 65536.0; + r_ave[2] = cs.loadavg[2] / 65536.0; + } +#elif defined(irix6) + SGT_COOKIE_INIT(&cookie); + SGT_COOKIE_SET_KSYM(&cookie, "avenrun"); + sysget(SGT_KSYM, (char*)favenrun, sizeof(favenrun), SGT_READ, &cookie); + for (i = 0; i < s_ave; i++) + r_ave[i] = favenrun[i] / 1000.0; + DEBUGMSGTL(("ucd-snmp/loadave", "irix6: %d %d %d\n", favenrun[0], favenrun[1], favenrun[2])); +#elif !defined(cygwin) +#if defined(NETSNMP_CAN_USE_NLIST) && defined(LOADAVE_SYMBOL) + if (auto_nlist(LOADAVE_SYMBOL, (char *) pave, sizeof(double) * s_ave) + == 0) +#endif + return (-1); +#endif + /* + * XXX + * To calculate this, we need to compare + * successive values of the kernel array + * '_cp_times', and calculate the resulting + * percentage changes. + * This calculation needs to be performed + * regularly - perhaps as a background process. + * + * See the source to 'top' for full details. + * + * The linux SNMP HostRes implementation + * uses 'avenrun[0]*100' as an approximation. + * This is less than accurate, but has the + * advantage of being simple to implement! + * + * I'm also assuming a single processor + */ + return 0; +} + +static int +write_laConfig(int action, + u_char * var_val, + u_char var_val_type, + size_t var_val_len, + u_char * statP, oid * name, size_t name_len) +{ + static double laConfig = 0; + + switch (action) { + case RESERVE1: /* Check values for acceptability */ + if (var_val_type != ASN_OCTET_STR) { + DEBUGMSGTL(("ucd-snmp/loadave", + "write to laConfig not ASN_OCTET_STR\n")); + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len > 8 || var_val_len <= 0) { + DEBUGMSGTL(("ucd-snmp/loadave", + "write to laConfig: bad length\n")); + return SNMP_ERR_WRONGLENGTH; + } + + if (laConfigSet < 0) { + /* + * The object is set in a read-only configuration file. + */ + return SNMP_ERR_NOTWRITABLE; + } + break; + + case RESERVE2: /* Allocate memory and similar resources */ + { + char buf[8]; + int old_errno = errno; + double val; + char *endp; + + sprintf(buf, "%.*s", (int) var_val_len, (char *)var_val); + val = strtod(buf, &endp); + + if (errno == ERANGE || *endp != '\0' || val < 0 || val > 65536.00) { + errno = old_errno; + DEBUGMSGTL(("ucd-snmp/loadave", + "write to laConfig: invalid value\n")); + return SNMP_ERR_WRONGVALUE; + } + + errno = old_errno; + + laConfig = val; + } + break; + + case COMMIT: + { + int idx = name[name_len - 1] - 1; + maxload[idx] = laConfig; + laConfigSet = 1; + } + } + + return SNMP_ERR_NOERROR; +} + +u_char * +var_extensible_loadave(struct variable * vp, + oid * name, + size_t * length, + int exact, + size_t * var_len, WriteMethod ** write_method) +{ + + static long long_ret; + static float float_ret; + static char errmsg[300]; + double avenrun[3]; + if (header_simple_table + (vp, name, length, exact, var_len, write_method, 3)) + return (NULL); + switch (vp->magic) { + case MIBINDEX: + long_ret = name[*length - 1]; + return ((u_char *) (&long_ret)); + case LOADMAXVAL: + /* setup write method, but don't return yet */ + *write_method = write_laConfig; + break; + case ERRORNAME: + sprintf(errmsg, "Load-%d", ((name[*length - 1] == 1) ? 1 : + ((name[*length - 1] == 2) ? 5 : 15))); + *var_len = strlen(errmsg); + return ((u_char *) (errmsg)); + } + if (try_getloadavg(&avenrun[0], sizeof(avenrun) / sizeof(avenrun[0])) + == -1) + return NULL; + switch (vp->magic) { + case LOADAVE: + + sprintf(errmsg, "%.2f", avenrun[name[*length - 1] - 1]); + *var_len = strlen(errmsg); + return ((u_char *) (errmsg)); + case LOADMAXVAL: + sprintf(errmsg, "%.2f", maxload[name[*length - 1] - 1]); + *var_len = strlen(errmsg); + return ((u_char *) (errmsg)); + case LOADAVEINT: + long_ret = (u_long) (avenrun[name[*length - 1] - 1] * 100); + return ((u_char *) (&long_ret)); +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + case LOADAVEFLOAT: + float_ret = (float) avenrun[name[*length - 1] - 1]; + *var_len = sizeof(float_ret); + return ((u_char *) (&float_ret)); +#endif + case ERRORFLAG: + long_ret = (maxload[name[*length - 1] - 1] != 0 && + avenrun[name[*length - 1] - 1] >= + maxload[name[*length - 1] - 1]) ? 1 : 0; + return ((u_char *) (&long_ret)); + case ERRORMSG: + if (maxload[name[*length - 1] - 1] != 0 && + avenrun[name[*length - 1] - 1] >= + maxload[name[*length - 1] - 1]) { + snprintf(errmsg, sizeof(errmsg), + "%d min Load Average too high (= %.2f)", + (name[*length - 1] == + 1) ? 1 : ((name[*length - 1] == 2) ? 5 : 15), + avenrun[name[*length - 1] - 1]); + errmsg[sizeof(errmsg) - 1] = '\0'; + } else { + errmsg[0] = 0; + } + *var_len = strlen(errmsg); + return ((u_char *) errmsg); + } + return NULL; +} |