1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-includes.h>
3 #include <net-snmp/agent/net-snmp-agent-includes.h>
4 #include <net-snmp/agent/hardware/memory.h>
5
6 #include <unistd.h>
7 #include <fcntl.h>
8
9 /*
10 * Try to use an initial size that will cover default cases. We aren't talking
11 * about huge files, so why fiddle about with reallocs?
12 */
13 #define MEMINFO_INIT_SIZE 4096
14 #define MEMINFO_STEP_SIZE 4096
15 #define MEMINFO_FILE "/proc/meminfo"
16
17 /*
18 * Load the latest memory usage statistics
19 */
netsnmp_mem_arch_load(netsnmp_cache * cache,void * magic)20 int netsnmp_mem_arch_load( netsnmp_cache *cache, void *magic ) {
21 int statfd;
22 static char *buff = NULL;
23 static int bsize = 0;
24 static int first = 1;
25 ssize_t bytes_read;
26 char *b;
27 unsigned long memtotal = 0, memfree = 0, memshared = 0,
28 buffers = 0, cached = 0, sreclaimable = 0,
29 swaptotal = 0, swapfree = 0;
30
31 netsnmp_memory_info *mem;
32
33 /*
34 * Retrieve the memory information from the underlying O/S...
35 */
36 if ((statfd = open(MEMINFO_FILE, O_RDONLY, 0)) == -1) {
37 snmp_log_perror(MEMINFO_FILE);
38 return -1;
39 }
40 if (bsize == 0) {
41 bsize = MEMINFO_INIT_SIZE;
42 buff = (char*)malloc(bsize+1);
43 if (NULL == buff) {
44 snmp_log(LOG_ERR, "malloc failed\n");
45 close(statfd);
46 return -1;
47 }
48 }
49 while ((bytes_read = read(statfd, buff, bsize)) == bsize) {
50 b = (char*)realloc(buff, bsize + MEMINFO_STEP_SIZE + 1);
51 if (NULL == b) {
52 snmp_log(LOG_ERR, "malloc failed\n");
53 close(statfd);
54 return -1;
55 }
56 buff = b;
57 bsize += MEMINFO_STEP_SIZE;
58 DEBUGMSGTL(("mem", "/proc/meminfo buffer increased to %d\n", bsize));
59 close(statfd);
60 statfd = open(MEMINFO_FILE, O_RDONLY, 0);
61 if (statfd == -1) {
62 snmp_log_perror(MEMINFO_FILE);
63 return -1;
64 }
65 }
66 close(statfd);
67 if (bytes_read <= 0) {
68 snmp_log_perror(MEMINFO_FILE);
69 buff[0] = '\0';
70 } else {
71 buff[bytes_read] = '\0';
72 }
73
74 /*
75 * ... parse this into a more useable form...
76 */
77 b = strstr(buff, "MemTotal: ");
78 if (b)
79 sscanf(b, "MemTotal: %lu", &memtotal);
80 else {
81 if (first)
82 snmp_log(LOG_ERR, "No MemTotal line in /proc/meminfo\n");
83 }
84 b = strstr(buff, "MemFree: ");
85 if (b)
86 sscanf(b, "MemFree: %lu", &memfree);
87 else {
88 if (first)
89 snmp_log(LOG_ERR, "No MemFree line in /proc/meminfo\n");
90 }
91 if (0 == netsnmp_os_prematch("Linux","2.4")) {
92 b = strstr(buff, "MemShared: ");
93 if (b)
94 sscanf(b, "MemShared: %lu", &memshared);
95 else if (first)
96 snmp_log(LOG_ERR, "No MemShared line in /proc/meminfo\n");
97 }
98 else {
99 b = strstr(buff, "Shmem: ");
100 if (b)
101 sscanf(b, "Shmem: %lu", &memshared);
102 else if (first)
103 snmp_log(LOG_ERR, "No Shmem line in /proc/meminfo\n");
104 }
105 b = strstr(buff, "Buffers: ");
106 if (b)
107 sscanf(b, "Buffers: %lu", &buffers);
108 else {
109 if (first)
110 snmp_log(LOG_ERR, "No Buffers line in /proc/meminfo\n");
111 }
112 b = strstr(buff, "Cached: ");
113 if (b)
114 sscanf(b, "Cached: %lu", &cached);
115 else {
116 if (first)
117 snmp_log(LOG_ERR, "No Cached line in /proc/meminfo\n");
118 }
119 b = strstr(buff, "SwapTotal: ");
120 if (b)
121 sscanf(b, "SwapTotal: %lu", &swaptotal);
122 else {
123 if (first)
124 snmp_log(LOG_ERR, "No SwapTotal line in /proc/meminfo\n");
125 }
126 b = strstr(buff, "SwapFree: ");
127 if (b)
128 sscanf(b, "SwapFree: %lu", &swapfree);
129 else {
130 if (first)
131 snmp_log(LOG_ERR, "No SwapFree line in /proc/meminfo\n");
132 }
133 b = strstr(buff, "SReclaimable: ");
134 if (b)
135 sscanf(b, "SReclaimable: %lu", &sreclaimable);
136 first = 0;
137
138
139 /*
140 * ... and save this in a standard form.
141 */
142 mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_PHYSMEM, 1 );
143 if (!mem) {
144 snmp_log_perror("No Physical Memory info entry");
145 } else {
146 if (!mem->descr)
147 mem->descr = strdup("Physical memory");
148 mem->units = 1024;
149 mem->size = memtotal;
150 mem->free = memfree;
151 mem->other = -1;
152 }
153
154 mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_VIRTMEM, 1 );
155 if (!mem) {
156 snmp_log_perror("No Virtual Memory info entry");
157 } else {
158 if (!mem->descr)
159 mem->descr = strdup("Virtual memory");
160 mem->units = 1024;
161 mem->size = memtotal+swaptotal;
162 mem->free = memfree +swapfree;
163 mem->other = -1;
164 }
165
166 mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SHARED, 1 );
167 if (!mem) {
168 snmp_log_perror("No Shared Memory info entry");
169 } else {
170 if (!mem->descr)
171 mem->descr = strdup("Shared memory");
172 mem->units = 1024;
173 mem->size = memshared;
174 mem->free = 0; /* All in use */
175 mem->other = -1;
176 }
177
178 mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_CACHED, 1 );
179 if (!mem) {
180 snmp_log_perror("No Cached Memory info entry");
181 } else {
182 if (!mem->descr)
183 mem->descr = strdup("Cached memory");
184 mem->units = 1024;
185 mem->size = cached + sreclaimable;
186 mem->free = 0; /* Report cached size/used as equal */
187 mem->other = -1;
188 }
189
190 mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP, 1 );
191 if (!mem) {
192 snmp_log_perror("No Swap info entry");
193 } else {
194 if (!mem->descr)
195 mem->descr = strdup("Swap space");
196 mem->units = 1024;
197 mem->size = swaptotal;
198 mem->free = swapfree;
199 mem->other = -1;
200 }
201
202 mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_MBUF, 1 );
203 if (!mem) {
204 snmp_log_perror("No Buffer, etc info entry");
205 } else {
206 if (!mem->descr)
207 mem->descr = strdup("Memory buffers");
208 mem->units = 1024;
209 mem->size = memtotal; /* Traditionally we've always regarded
210 all memory as potentially available
211 for memory buffers. */
212 mem->free = memtotal - buffers;
213 mem->other = -1;
214 }
215
216 return 0;
217 }
218