#include #if HAVE_STDLIB_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_FCNTL_H #include #endif #include #if HAVE_MACHINE_PARAM_H #include #endif #if HAVE_SYS_PARAM_H #include #endif #if HAVE_SYS_VMMETER_H #if !(defined(bsdi2) || defined(netbsd1)) #include #endif #endif #if HAVE_SYS_CONF_H #include #endif #if HAVE_ASM_PAGE_H #include #endif #if HAVE_SYS_SWAP_H #include #endif #if HAVE_SYS_FS_H #include #else #if HAVE_UFS_FS_H #include #else #ifdef HAVE_SYS_STAT_H #include #endif #if !defined(dragonfly) #ifdef HAVE_SYS_VNODE_H #include #endif #endif #ifdef HAVE_UFS_UFS_QUOTA_H #include #endif #ifdef HAVE_UFS_UFS_INODE_H #include #endif #if HAVE_UFS_FFS_FS_H #include #endif #endif #endif #if HAVE_MTAB_H #include #endif #include #if HAVE_FSTAB_H #include #endif #if HAVE_SYS_STATFS_H #include #endif #if HAVE_SYS_STATVFS_H #include #endif #if HAVE_SYS_VFS_H #include #endif #if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS) #if HAVE_SYS_MOUNT_H #include #endif #if HAVE_SYS_SYSCTL_H #include #endif #define statvfs statfs #endif #if HAVE_VM_VM_H #include #endif #if HAVE_VM_SWAP_PAGER_H #include #endif #if HAVE_SYS_FIXPOINT_H #include #endif #if HAVE_SYS_LOADAVG_H #include #endif #if HAVE_MALLOC_H #include #endif #if HAVE_STRING_H #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef dynix #include #endif #if defined(hpux10) || defined(hpux11) #include #endif #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) #ifdef HAVE_SYS_PROTOSW_H #include #endif #include #endif #if HAVE_SYS_SYSGET_H #include #endif #include #include #include #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) { #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) 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(r_ave, 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", r_ave, (r_ave + 1), (r_ave + 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++) *(r_ave + 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 *) r_ave, 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; }