#include #if HAVE_LIMITS_H #include #endif #if HAVE_STDLIB_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_FCNTL_H #include #endif #include #include #if HAVE_MACHINE_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_SYS_FS_H #include #else #if HAVE_UFS_FS_H #include #else #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_SYS_VNODE_H #include #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 #include #if HAVE_FSTAB_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_PARAM_H #include #endif #if HAVE_SYS_MOUNT_H #include #endif #if HAVE_SYS_SYSCTL_H #include #endif #define statvfs statfs #endif #if HAVE_VM_SWAP_PAGER_H #include #endif #if HAVE_SYS_FIXPOINT_H #include #endif #if HAVE_MALLOC_H #include #endif #if HAVE_STRING_H #include #else #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #include #include #include #include #include "mibdefs.h" #include "struct.h" #include "util_funcs.h" #include "vmstat.h" FindVarMethod var_extensible_vmstat; static int has_vmstat = 1; static int has_cpu_26 = 1; static time_t cache_time; #define CACHE_TIMEOUT 5 #define STAT_FILE "/proc/stat" #define VMSTAT_FILE "/proc/vmstat" void init_vmstat(void) { struct variable2 extensible_vmstat_variables[] = { {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {MIBINDEX}}, {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_vmstat, 1, {ERRORNAME}}, {SWAPIN, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {SWAPIN}}, {SWAPOUT, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {SWAPOUT}}, {RAWSWAPIN, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {RAWSWAPIN}}, {RAWSWAPOUT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {RAWSWAPOUT}}, {IOSENT, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {IOSENT}}, {IORECEIVE, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {IORECEIVE}}, {IORAWSENT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {IORAWSENT}}, {IORAWRECEIVE, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {IORAWRECEIVE}}, {SYSINTERRUPTS, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {SYSINTERRUPTS}}, {SYSCONTEXT, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {SYSCONTEXT}}, {CPUUSER, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {CPUUSER}}, {CPUSYSTEM, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {CPUSYSTEM}}, {CPUIDLE, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {CPUIDLE}}, {CPURAWUSER, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWUSER}}, {CPURAWNICE, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWNICE}}, {CPURAWSYSTEM, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWSYSTEM}}, {CPURAWKERNEL, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWKERNEL}}, {CPURAWIDLE, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWIDLE}}, {SYSRAWINTERRUPTS, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {SYSRAWINTERRUPTS}}, {SYSRAWCONTEXT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {SYSRAWCONTEXT}}, {CPURAWWAIT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWWAIT}}, {CPURAWINTR, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWINTR}}, {CPURAWSOFTIRQ, ASN_COUNTER, RONLY, var_extensible_vmstat, 1, {CPURAWSOFTIRQ}}, /* * Future use: */ /* * {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {ERRORFLAG }}, * {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_vmstat, 1, {ERRORMSG }} */ }; /* * Define the OID pointer to the top of the mib tree that we're * registering underneath */ oid vmstat_variables_oid[] = { UCDAVIS_MIB, 11 }; /* * register ourselves with the agent to handle our mib tree */ REGISTER_MIB("ucd-snmp/vmstat", extensible_vmstat_variables, variable2, vmstat_variables_oid); } static void getstat(unsigned long *cuse, unsigned long *cice, unsigned long *csys, unsigned long *cide, unsigned *pin, unsigned *pout, unsigned *swpin, unsigned *swpout, unsigned *itot, unsigned *i1, unsigned *ct, unsigned long *ciow, unsigned long *cirq, unsigned long *csoft) { int statfd, vmstatfd; static int first = 1; static char *buff = NULL, *vmbuff = NULL; static int bsize = 0, vmbsize = 0; char *b, *c; time_t now; unsigned long long cpunum; unsigned long long cusell = 0, cicell = 0, csysll = 0, cidell = 0, ciowll = 0, cirqll = 0, csoftll = 0, ctll = 0, itotll = 0, i1ll = 0; time(&now); if (cache_time + CACHE_TIMEOUT < now) { if ((statfd = open(STAT_FILE, O_RDONLY, 0)) == -1) { snmp_log_perror(STAT_FILE); return; } if (bsize == 0) { bsize = 256; buff = malloc(bsize); } while (read(statfd, buff, bsize) == bsize) { bsize += 256; buff = realloc(buff, bsize); DEBUGMSGTL(("vmstat", "/proc/stat buffer increased to %d\n", bsize)); close(statfd); statfd = open(STAT_FILE, O_RDONLY, 0); } close(statfd); if (has_vmstat && (vmstatfd = open(VMSTAT_FILE, O_RDONLY, 0)) != -1) { if (vmbsize == 0) { vmbsize = 256; vmbuff = malloc(vmbsize); } while (read(vmstatfd, vmbuff, vmbsize) == vmbsize) { vmbsize += 256; vmbuff = realloc(vmbuff, vmbsize); close(vmstatfd); vmstatfd = open(VMSTAT_FILE, O_RDONLY, 0); } close(vmstatfd); } else has_vmstat = 0; cache_time = now; } *itot = 0; *i1 = 1; c = buff; while ((c = strstr(c+1, "cpu")) != NULL) b = c; sscanf(b, "cpu%llu", &cpunum); cpunum++; b = strstr(buff, "cpu "); if (b) { if (!has_cpu_26 || sscanf(b, "cpu %llu %llu %llu %llu %llu %llu %llu", &cusell, &cicell, &csysll, &cidell, &ciowll, &cirqll, &csoftll) != 7) { has_cpu_26 = 0; sscanf(b, "cpu %llu %llu %llu %llu", &cusell, &cicell, &csysll, &cidell); *ciow = *cirq = *csoft = 0; } else { *ciow = (unsigned long)(ciowll/cpunum); *cirq = (unsigned long)(cirqll/cpunum); *csoft = (unsigned long)(csoftll/cpunum); } *cuse = (unsigned long)(cusell/cpunum); *cice = (unsigned long)(cicell/cpunum); *csys = (unsigned long)(csysll/cpunum); *cide = (unsigned long)(cidell/cpunum); } else { if (first) snmp_log(LOG_ERR, "No cpu line in %s\n", STAT_FILE); *cuse = *cice = *csys = *cide = *ciow = *cirq = *csoft = 0; } if (has_vmstat) { b = strstr(vmbuff, "pgpgin "); if (b) sscanf(b, "pgpgin %u", pin); else { if (first) snmp_log(LOG_ERR, "No pgpgin line in %s\n", VMSTAT_FILE); *pin = 0; } b = strstr(vmbuff, "pgpgout "); if (b) sscanf(b, "pgpgout %u", pout); else { if (first) snmp_log(LOG_ERR, "No pgpgout line in %s\n", VMSTAT_FILE); *pout = 0; } b = strstr(vmbuff, "pswpin "); if (b) sscanf(b, "pswpin %u", swpin); else { if (first) snmp_log(LOG_ERR, "No pswpin line in %s\n", VMSTAT_FILE); *swpin = 0; } b = strstr(vmbuff, "pswpout "); if (b) sscanf(b, "pswpout %u", swpout); else { if (first) snmp_log(LOG_ERR, "No pswpout line in %s\n", VMSTAT_FILE); *swpout = 0; } } else { b = strstr(buff, "page "); if (b) sscanf(b, "page %u %u", pin, pout); else { if (first) snmp_log(LOG_ERR, "No page line in %s\n", STAT_FILE); *pin = *pout = 0; } b = strstr(buff, "swap "); if (b) sscanf(b, "swap %u %u", swpin, swpout); else { if (first) snmp_log(LOG_ERR, "No swap line in %s\n", STAT_FILE); *swpin = *swpout = 0; } } b = strstr(buff, "intr "); if (b) { sscanf(b, "intr %llu %llu", &itotll, &i1ll); *itot = (unsigned)itotll; *i1 = (unsigned)i1ll; } else { if (first) snmp_log(LOG_ERR, "No intr line in %s\n", STAT_FILE); *itot = 0; } b = strstr(buff, "ctxt "); if (b) { sscanf(b, "ctxt %llu", &ctll); *ct = (unsigned long)ctll; } else { if (first) snmp_log(LOG_ERR, "No ctxt line in %s\n", STAT_FILE); *ct = 0; } first = 0; } enum vmstat_index { swapin = 0, swapout, rawswapin, rawswapout, iosent, ioreceive, rawiosent, rawioreceive, sysinterrupts, syscontext, cpuuser, cpusystem, cpuidle, cpurawuser, cpurawnice, cpurawsystem, cpurawidle, cpurawinter, cpurawsoft, cpurawwait, rawinterrupts, rawcontext }; static unsigned vmstat(int iindex) { double duse, dsys, didl, ddiv, divo2; double druse, drnic, drsys, dridl; unsigned int hertz; double ddiv2; netsnmp_cpu_info *cpu; netsnmp_cpu_load(); cpu = netsnmp_cpu_get_byIdx( -1, 0 ); duse = cpu->user_ticks + cpu->nice_ticks; dsys = cpu->sys_ticks; didl = cpu->idle_ticks; ddiv = duse + dsys + didl; hertz = sysconf(_SC_CLK_TCK); /* get ticks/s from system */ divo2 = ddiv / 2; druse = cpu->user_ticks; drnic = cpu->nice_ticks; drsys = cpu->sys_ticks; dridl = cpu->idle_ticks; ddiv2 = ddiv + cpu->wait_ticks + cpu->intrpt_ticks + cpu->sirq_ticks; if (cpu->history) { duse -= (cpu->history[0].user_hist + cpu->history[0].nice_hist); dsys -= cpu->history[0].sys_hist; didl -= cpu->history[0].idle_hist; ddiv2 -= cpu->history[0].total_hist; } if (!ddiv) ddiv=1; /* Protect against division-by-0 */ switch (iindex) { case swapin: return (cpu->swapIn * 4 * hertz + divo2) / ddiv; case swapout: return (cpu->swapOut * 4 * hertz + divo2) / ddiv; case iosent: return (cpu->pageIn * hertz + divo2) / ddiv; case ioreceive: return (cpu->pageOut * hertz + divo2) / ddiv; case sysinterrupts: return (cpu->nInterrupts * hertz + divo2) / ddiv; case syscontext: return (cpu->nCtxSwitches * hertz + divo2) / ddiv; case cpuuser: return (ddiv2 ? 100 * duse / ddiv2 : 0); case cpusystem: return (ddiv2 ? 100 * dsys / ddiv2 : 0); case cpuidle: return (ddiv2 ? 100 * didl / ddiv2 : 0); case cpurawuser: return druse; case cpurawnice: return drnic; case cpurawsystem: return drsys; case cpurawidle: return dridl; case rawinterrupts: return cpu->nInterrupts; case rawcontext: return cpu->nCtxSwitches; case cpurawwait: return cpu->wait_ticks; case cpurawinter: return cpu->intrpt_ticks; case cpurawsoft: return cpu->sirq_ticks; case rawiosent: return cpu->pageOut*2; case rawioreceive: return cpu->pageIn*2; case rawswapin: return cpu->swapIn; case rawswapout: return cpu->swapOut; default: return -1; } } unsigned char * var_extensible_vmstat(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { static long long_ret; static char errmsg[300]; long_ret = 0; /* set to 0 as default */ if (header_generic(vp, name, length, exact, var_len, write_method)) return (NULL); switch (vp->magic) { case MIBINDEX: long_ret = 1; return ((u_char *) (&long_ret)); case ERRORNAME: /* dummy name */ sprintf(errmsg, "systemStats"); *var_len = strlen(errmsg); return ((u_char *) (errmsg)); case SWAPIN: long_ret = vmstat(swapin); return ((u_char *) (&long_ret)); case SWAPOUT: long_ret = vmstat(swapout); return ((u_char *) (&long_ret)); case RAWSWAPIN: long_ret = vmstat(rawswapin); return ((u_char *) (&long_ret)); case RAWSWAPOUT: long_ret = vmstat(rawswapout); return ((u_char *) (&long_ret)); case IOSENT: long_ret = vmstat(iosent); return ((u_char *) (&long_ret)); case IORECEIVE: long_ret = vmstat(ioreceive); return ((u_char *) (&long_ret)); case IORAWSENT: long_ret = vmstat(rawiosent); return ((u_char *) (&long_ret)); case IORAWRECEIVE: long_ret = vmstat(rawioreceive); return ((u_char *) (&long_ret)); case SYSINTERRUPTS: long_ret = vmstat(sysinterrupts); return ((u_char *) (&long_ret)); case SYSCONTEXT: long_ret = vmstat(syscontext); return ((u_char *) (&long_ret)); case CPUUSER: long_ret = vmstat(cpuuser); return ((u_char *) (&long_ret)); case CPUSYSTEM: long_ret = vmstat(cpusystem); return ((u_char *) (&long_ret)); case CPUIDLE: long_ret = vmstat(cpuidle); return ((u_char *) (&long_ret)); case CPURAWUSER: long_ret = vmstat(cpurawuser); return ((u_char *) (&long_ret)); case CPURAWNICE: long_ret = vmstat(cpurawnice); return ((u_char *) (&long_ret)); case CPURAWSYSTEM: long_ret = vmstat(cpurawsystem)+vmstat(cpurawinter)+vmstat(cpurawsoft); return ((u_char *) (&long_ret)); case CPURAWKERNEL: long_ret = vmstat(cpurawsystem); return ((u_char *) (&long_ret)); case CPURAWIDLE: long_ret = vmstat(cpurawidle); return ((u_char *) (&long_ret)); case SYSRAWINTERRUPTS: long_ret = vmstat(rawinterrupts); return (u_char *)&long_ret; case SYSRAWCONTEXT: long_ret = vmstat(rawcontext); return (u_char *)&long_ret; case CPURAWWAIT: if (!has_cpu_26) return NULL; long_ret = vmstat(cpurawwait); return ((u_char *) (&long_ret)); case CPURAWINTR: if (!has_cpu_26) return NULL; long_ret = vmstat(cpurawinter); return ((u_char *) (&long_ret)); case CPURAWSOFTIRQ: if (!has_cpu_26) return NULL; long_ret = vmstat(cpurawsoft); return ((u_char *) (&long_ret)); /* * reserved for future use */ /* * case ERRORFLAG: * return((u_char *) (&long_ret)); * case ERRORMSG: * return((u_char *) (&long_ret)); */ default: snmp_log(LOG_ERR, "vmstat.c: don't know how to handle %d request\n", vp->magic); } return NULL; }