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