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