|
Packit |
a30ac4 |
#include <net-snmp/net-snmp-config.h>
|
|
Packit |
a30ac4 |
#include <net-snmp/net-snmp-includes.h>
|
|
Packit |
a30ac4 |
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
|
Packit |
a30ac4 |
#include <net-snmp/agent/hardware/memory.h>
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
#include <unistd.h>
|
|
Packit |
a30ac4 |
#include <fcntl.h>
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
/*
|
|
Packit |
a30ac4 |
* Try to use an initial size that will cover default cases. We aren't talking
|
|
Packit |
a30ac4 |
* about huge files, so why fiddle about with reallocs?
|
|
Packit |
a30ac4 |
* I checked /proc/meminfo sizes on 3 different systems: 598, 644, 654
|
|
Packit |
a30ac4 |
*
|
|
Packit |
a30ac4 |
* On newer systems, the size is up to around 930 (2.6.27 kernel)
|
|
Packit |
a30ac4 |
* or 1160 (2.6.28 kernel)
|
|
Packit |
a30ac4 |
*/
|
|
Packit |
a30ac4 |
#define MEMINFO_INIT_SIZE 1279
|
|
Packit |
a30ac4 |
#define MEMINFO_STEP_SIZE 256
|
|
Packit |
a30ac4 |
#define MEMINFO_FILE "/proc/meminfo"
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
/*
|
|
Packit |
a30ac4 |
* Load the latest memory usage statistics
|
|
Packit |
a30ac4 |
*/
|
|
Packit |
a30ac4 |
int netsnmp_mem_arch_load( netsnmp_cache *cache, void *magic ) {
|
|
Packit |
a30ac4 |
int statfd;
|
|
Packit |
a30ac4 |
static char *buff = NULL;
|
|
Packit |
a30ac4 |
static int bsize = 0;
|
|
Packit |
a30ac4 |
static int first = 1;
|
|
Packit |
a30ac4 |
ssize_t bytes_read;
|
|
Packit |
a30ac4 |
char *b;
|
|
Packit |
a30ac4 |
unsigned long memtotal = 0, memfree = 0, memshared = 0,
|
|
Packit |
a30ac4 |
buffers = 0, cached = 0,
|
|
Packit |
a30ac4 |
swaptotal = 0, swapfree = 0;
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
netsnmp_memory_info *mem;
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
/*
|
|
Packit |
a30ac4 |
* Retrieve the memory information from the underlying O/S...
|
|
Packit |
a30ac4 |
*/
|
|
Packit |
a30ac4 |
if ((statfd = open(MEMINFO_FILE, O_RDONLY, 0)) == -1) {
|
|
Packit |
a30ac4 |
snmp_log_perror(MEMINFO_FILE);
|
|
Packit |
a30ac4 |
return -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
if (bsize == 0) {
|
|
Packit |
a30ac4 |
bsize = MEMINFO_INIT_SIZE;
|
|
Packit |
a30ac4 |
buff = (char*)malloc(bsize+1);
|
|
Packit |
a30ac4 |
if (NULL == buff) {
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "malloc failed\n");
|
|
Packit |
a30ac4 |
close(statfd);
|
|
Packit |
a30ac4 |
return -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
while ((bytes_read = read(statfd, buff, bsize)) == bsize) {
|
|
Packit |
a30ac4 |
b = (char*)realloc(buff, bsize + MEMINFO_STEP_SIZE + 1);
|
|
Packit |
a30ac4 |
if (NULL == b) {
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "malloc failed\n");
|
|
Packit |
a30ac4 |
close(statfd);
|
|
Packit |
a30ac4 |
return -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
buff = b;
|
|
Packit |
a30ac4 |
bsize += MEMINFO_STEP_SIZE;
|
|
Packit |
a30ac4 |
DEBUGMSGTL(("mem", "/proc/meminfo buffer increased to %d\n", bsize));
|
|
Packit |
a30ac4 |
close(statfd);
|
|
Packit |
a30ac4 |
statfd = open(MEMINFO_FILE, O_RDONLY, 0);
|
|
Packit |
a30ac4 |
if (statfd == -1) {
|
|
Packit |
a30ac4 |
snmp_log_perror(MEMINFO_FILE);
|
|
Packit |
a30ac4 |
return -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
close(statfd);
|
|
Packit |
a30ac4 |
if (bytes_read <= 0) {
|
|
Packit |
a30ac4 |
snmp_log_perror(MEMINFO_FILE);
|
|
Packit |
a30ac4 |
buff[0] = '\0';
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
buff[bytes_read] = '\0';
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
/*
|
|
Packit |
a30ac4 |
* ... parse this into a more useable form...
|
|
Packit |
a30ac4 |
*/
|
|
Packit |
a30ac4 |
b = strstr(buff, "MemTotal: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "MemTotal: %lu", &memtotal);
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No MemTotal line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
b = strstr(buff, "MemFree: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "MemFree: %lu", &memfree);
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No MemFree line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
if (0 == netsnmp_os_prematch("Linux","2.4")) {
|
|
Packit |
a30ac4 |
b = strstr(buff, "MemShared: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "MemShared: %lu", &memshared);
|
|
Packit |
a30ac4 |
else if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No MemShared line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
b = strstr(buff, "Shmem: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "Shmem: %lu", &memshared);
|
|
Packit |
a30ac4 |
else if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No Shmem line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
b = strstr(buff, "Buffers: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "Buffers: %lu", &buffers);
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No Buffers line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
b = strstr(buff, "Cached: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "Cached: %lu", &cached);
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No Cached line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
b = strstr(buff, "SwapTotal: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "SwapTotal: %lu", &swaptotal);
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No SwapTotal line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
b = strstr(buff, "SwapFree: ");
|
|
Packit |
a30ac4 |
if (b)
|
|
Packit |
a30ac4 |
sscanf(b, "SwapFree: %lu", &swapfree);
|
|
Packit |
a30ac4 |
else {
|
|
Packit |
a30ac4 |
if (first)
|
|
Packit |
a30ac4 |
snmp_log(LOG_ERR, "No SwapFree line in /proc/meminfo\n");
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
first = 0;
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
/*
|
|
Packit |
a30ac4 |
* ... and save this in a standard form.
|
|
Packit |
a30ac4 |
*/
|
|
Packit |
a30ac4 |
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_PHYSMEM, 1 );
|
|
Packit |
a30ac4 |
if (!mem) {
|
|
Packit |
a30ac4 |
snmp_log_perror("No Physical Memory info entry");
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
if (!mem->descr)
|
|
Packit |
a30ac4 |
mem->descr = strdup("Physical memory");
|
|
Packit |
a30ac4 |
mem->units = 1024;
|
|
Packit |
a30ac4 |
mem->size = memtotal;
|
|
Packit |
a30ac4 |
mem->free = memfree;
|
|
Packit |
a30ac4 |
mem->other = -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_VIRTMEM, 1 );
|
|
Packit |
a30ac4 |
if (!mem) {
|
|
Packit |
a30ac4 |
snmp_log_perror("No Virtual Memory info entry");
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
if (!mem->descr)
|
|
Packit |
a30ac4 |
mem->descr = strdup("Virtual memory");
|
|
Packit |
a30ac4 |
mem->units = 1024;
|
|
Packit |
a30ac4 |
mem->size = memtotal+swaptotal;
|
|
Packit |
a30ac4 |
mem->free = memfree +swapfree;
|
|
Packit |
a30ac4 |
mem->other = -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SHARED, 1 );
|
|
Packit |
a30ac4 |
if (!mem) {
|
|
Packit |
a30ac4 |
snmp_log_perror("No Shared Memory info entry");
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
if (!mem->descr)
|
|
Packit |
a30ac4 |
mem->descr = strdup("Shared memory");
|
|
Packit |
a30ac4 |
mem->units = 1024;
|
|
Packit |
a30ac4 |
mem->size = memshared;
|
|
Packit |
a30ac4 |
mem->free = 0; /* All in use */
|
|
Packit |
a30ac4 |
mem->other = -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_CACHED, 1 );
|
|
Packit |
a30ac4 |
if (!mem) {
|
|
Packit |
a30ac4 |
snmp_log_perror("No Cached Memory info entry");
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
if (!mem->descr)
|
|
Packit |
a30ac4 |
mem->descr = strdup("Cached memory");
|
|
Packit |
a30ac4 |
mem->units = 1024;
|
|
Packit |
a30ac4 |
mem->size = cached;
|
|
Packit |
a30ac4 |
mem->free = 0; /* Report cached size/used as equal */
|
|
Packit |
a30ac4 |
mem->other = -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP, 1 );
|
|
Packit |
a30ac4 |
if (!mem) {
|
|
Packit |
a30ac4 |
snmp_log_perror("No Swap info entry");
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
if (!mem->descr)
|
|
Packit |
a30ac4 |
mem->descr = strdup("Swap space");
|
|
Packit |
a30ac4 |
mem->units = 1024;
|
|
Packit |
a30ac4 |
mem->size = swaptotal;
|
|
Packit |
a30ac4 |
mem->free = swapfree;
|
|
Packit |
a30ac4 |
mem->other = -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_MBUF, 1 );
|
|
Packit |
a30ac4 |
if (!mem) {
|
|
Packit |
a30ac4 |
snmp_log_perror("No Buffer, etc info entry");
|
|
Packit |
a30ac4 |
} else {
|
|
Packit |
a30ac4 |
if (!mem->descr)
|
|
Packit |
a30ac4 |
mem->descr = strdup("Memory buffers");
|
|
Packit |
a30ac4 |
mem->units = 1024;
|
|
Packit |
a30ac4 |
mem->size = memtotal; /* Traditionally we've always regarded
|
|
Packit |
a30ac4 |
all memory as potentially available
|
|
Packit |
a30ac4 |
for memory buffers. */
|
|
Packit |
a30ac4 |
mem->free = memtotal - buffers;
|
|
Packit |
a30ac4 |
mem->other = -1;
|
|
Packit |
a30ac4 |
}
|
|
Packit |
a30ac4 |
|
|
Packit |
a30ac4 |
return 0;
|
|
Packit |
a30ac4 |
}
|