blob: 2548ed88d1c4c45d1a210ef4f1d88ce8b30ab943 [file] [log] [blame]
#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
# ifdef WIN32
# include <sys/timeb.h>
# else
# include <sys/time.h>
# endif
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_WINSOCK_H
#include <winsock.h>
#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)
#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"
double maxload[3];
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_RONLY,
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);
snmpd_register_config_handler("load", loadave_parse_config,
loadave_free_config,
"max1 [max5] [max15]");
}
void
loadave_parse_config(const char *token, char *cptr)
{
int i;
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)
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) {
snmp_log(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)
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;
}
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 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;
}