1 #include <net-snmp/net-snmp-config.h>
14 #if HAVE_MACHINE_PARAM_H
15 #include <machine/param.h>
17 #if HAVE_SYS_VMMETER_H
18 #if !defined(bsdi2) && !defined(netbsd1)
19 #include <sys/vmmeter.h>
37 #ifdef HAVE_SYS_STAT_H
40 #ifdef HAVE_SYS_VNODE_H
41 #include <sys/vnode.h>
43 #ifdef HAVE_UFS_UFS_QUOTA_H
44 #include <ufs/ufs/quota.h>
46 #ifdef HAVE_UFS_UFS_INODE_H
47 #include <ufs/ufs/inode.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
53 #include <ufs/ffs/fs.h>
65 #if HAVE_SYS_STATVFS_H
66 #include <sys/statvfs.h>
71 #if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS)
73 #include <sys/param.h>
76 #include <sys/mount.h>
79 #include <sys/sysctl.h>
81 #define statvfs statfs
83 #if HAVE_VM_SWAP_PAGER_H
84 #include <vm/swap_pager.h>
86 #if HAVE_SYS_FIXPOINT_H
87 #include <sys/fixpoint.h>
95 #if TIME_WITH_SYS_TIME
96 # include <sys/time.h>
100 # include <sys/time.h>
105 #if defined(hpux10) || defined(hpux11)
106 #include <sys/pstat.h>
109 #include <net-snmp/net-snmp-includes.h>
110 #include <net-snmp/agent/net-snmp-agent-includes.h>
111 #include <net-snmp/agent/auto_nlist.h>
115 #include "util_funcs.h"
120 static int pageshift; /* log base 2 of the pagesize */
124 #ifdef NSWAPDEV_SYMBOL
125 int nswapdev=10; /* taken from <machine/space.h> */
127 #ifdef NSWAPFS_SYMBOL
128 int nswapfs=10; /* taken from <machine/space.h> */
132 #define DEFAULTMINIMUMSWAP 16000 /* kilobytes */
134 static FindVarMethod var_extensible_mem;
141 #ifdef PHYSMEM_SYMBOL
142 auto_nlist(PHYSMEM_SYMBOL, 0, 0);
144 #ifdef TOTAL_MEMORY_SYMBOL
145 auto_nlist(TOTAL_MEMORY_SYMBOL, 0, 0);
148 auto_nlist(MBSTAT_SYMBOL, 0, 0);
151 auto_nlist(SWDEVT_SYMBOL, 0, 0);
153 #ifdef FSWDEVT_SYMBOL
154 auto_nlist(FSWDEVT_SYMBOL, 0, 0);
156 #ifdef NSWAPFS_SYMBOL
157 auto_nlist(NSWAPFS_SYMBOL, 0, 0);
159 #ifdef NSWAPDEV_SYMBOL
160 auto_nlist(NSWAPDEV_SYMBOL, 0, 0);
164 #ifdef NSWAPDEV_SYMBOL
165 if (auto_nlist(NSWAPDEV_SYMBOL, (char *) &nswapdev, sizeof(nswapdev))
169 #ifdef NSWAPFS_SYMBOL
170 if (auto_nlist(NSWAPFS_SYMBOL, (char *) &nswapfs, sizeof(nswapfs)) ==
175 pagesize = 1 << PGSHIFT;
177 while (pagesize > 1) {
184 struct variable2 extensible_mem_variables[] = {
185 {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_mem, 1,
187 {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_mem, 1,
189 {MEMTOTALSWAP, ASN_INTEGER, RONLY, var_extensible_mem, 1,
191 {MEMAVAILSWAP, ASN_INTEGER, RONLY, var_extensible_mem, 1,
193 {MEMTOTALREAL, ASN_INTEGER, RONLY, var_extensible_mem, 1,
195 {MEMAVAILREAL, ASN_INTEGER, RONLY, var_extensible_mem, 1,
197 {MEMTOTALSWAPTXT, ASN_INTEGER, RONLY, var_extensible_mem, 1,
199 {MEMUSEDSWAPTXT, ASN_INTEGER, RONLY, var_extensible_mem, 1,
201 {MEMTOTALREALTXT, ASN_INTEGER, RONLY, var_extensible_mem, 1,
203 {MEMUSEDREALTXT, ASN_INTEGER, RONLY, var_extensible_mem, 1,
205 {MEMTOTALFREE, ASN_INTEGER, RONLY, var_extensible_mem, 1,
207 {MEMSWAPMINIMUM, ASN_INTEGER, RONLY, var_extensible_mem, 1,
209 {MEMSHARED, ASN_INTEGER, RONLY, var_extensible_mem, 1,
211 {MEMBUFFER, ASN_INTEGER, RONLY, var_extensible_mem, 1,
213 {MEMCACHED, ASN_INTEGER, RONLY, var_extensible_mem, 1,
215 {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_mem, 1,
217 {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_mem, 1,
222 * Define the OID pointer to the top of the mib tree that we're
223 * registering underneath
225 oid mem_variables_oid[] = { UCDAVIS_MIB, MEMMIBNUM };
228 * register ourselves with the agent to handle our mib tree
230 REGISTER_MIB("ucd-snmp/memory", extensible_mem_variables,
231 variable2, mem_variables_oid);
233 snmpd_register_config_handler("swap", memory_parse_config,
234 memory_free_config, "min-avail");
239 memory_parse_config(const char *token, char *cptr)
241 minimumswap = atoi(cptr);
245 memory_free_config(void)
247 minimumswap = DEFAULTMINIMUMSWAP;
251 enum meminfo_row { meminfo_main = 0,
255 enum meminfo_col { meminfo_total = 0, meminfo_used, meminfo_free,
256 meminfo_shared, meminfo_buffers, meminfo_cached
258 #define MEMINFO_FILE "/proc/meminfo"
260 static char buf[300];
263 * This macro opens FILE only if necessary and seeks to 0 so that successive
264 * calls to the functions are more efficient. It also reads the current
265 * contents of the file into the global buf.
267 #define FILE_TO_BUF(FILE) { \
268 static int n, fd = -1; \
269 if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \
272 lseek(fd, 0L, SEEK_SET); \
273 if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \
281 #define MAX_ROW 3 /* these are a little liberal for flexibility */
287 static unsigned *row[MAX_ROW + 1]; /* row pointers */
288 static unsigned num[MAX_ROW * MAX_COL]; /* number storage */
293 FILE_TO_BUF(MEMINFO_FILE)
294 if (!row[0]) /* init ptrs 1st time through */
295 for (i = 0; i < MAX_ROW; i++) /* std column major order: */
296 row[i] = num + MAX_COL * i; /* A[i][j] = A + COLS*i + j */
298 for (i = 0; i < MAX_ROW; i++) /* zero unassigned fields */
299 for (j = 0; j < MAX_COL; j++)
301 for (i = 0; i < MAX_ROW && *p; i++) { /* loop over rows */
302 while (*p && !isdigit(*p))
303 p++; /* skip chars until a digit */
304 for (j = 0; j < MAX_COL && *p; j++) { /* scanf column-by-column */
305 l = sscanf(p, "%lu%n", &m, &k);
307 if (0x7fffffff < m) {
308 *(row[i] + j) = 0x7fffffff;
310 *(row[i] + j) = (unsigned) m;
312 p += k; /* step over used buffer */
313 if (*p == '\n' || l < 1) /* end of line/buffer */
318 * row[i+1] = NULL; terminate the row list, currently unnecessary
320 return row; /* NULL return ==> error */
326 unsigned **mem = meminfo();
328 return mem[meminfo_main][iindex];
336 unsigned **mem = meminfo();
338 return mem[meminfo_swap][iindex];
343 #define pagetok(size) ((size) << pageshift)
346 #define SWAPGETLEFT 0
347 #define SWAPGETTOTAL 1
352 long spaceleft = 0, spacetotal = 0;
355 spaceleft = memswap(meminfo_free);
356 spacetotal = memswap(meminfo_total);
358 struct swapstats swapst;
359 size_t size = sizeof(swapst);
360 static int mib[] = { CTL_VM, VM_SWAPSTATS };
361 if (sysctl(mib, 2, &swapst, &size, NULL, 0) < 0)
363 spaceleft = swapst.swap_free / 2;
364 spacetotal = swapst.swap_total / 2;
365 #elif defined (hpux10) || defined(hpux11)
366 struct pst_swapinfo pst_buf;
370 while (pstat_getswap(&pst_buf, sizeof(struct pst_swapinfo), 1, ndx) > 0) {
371 if (pst_buf.pss_flags & SW_BLOCK) {
372 pgs = pst_buf.pss_nblksenabled;
373 pgs_free = pst_buf.pss_nblksavail;
375 else if (pst_buf.pss_flags & SW_FS) {
376 pgs = pst_buf.pss_limit;
377 pgs_free = pgs - pst_buf.pss_allocated - pst_buf.pss_reserve;
379 * the following calculation is done this way to avoid integer overflow!
380 * pss_swapchunk is either 512 or a multiple of 1024!
382 if (pst_buf.pss_swapchunk == 512) {
386 pgs_free *= (pst_buf.pss_swapchunk / 1024);
387 pgs *= (pst_buf.pss_swapchunk / 1024);
393 spaceleft += pgs_free;
395 ndx = pst_buf.pss_idx + 1;
397 #else /* !linux && !bsdi2 && !hpux10 && !hpux11 */
398 struct swdevt swdevt[100];
399 struct fswdevt fswdevt[100];
401 struct extensible ex;
406 (SWDEVT_SYMBOL, (char *) swdevt, sizeof(struct swdevt) * nswapdev)
409 DEBUGMSGTL(("ucd-snmp/memory", "%d block swap devices: \n", nswapdev));
410 for (i = 0; i < nswapdev; i++) {
411 DEBUGMSGTL(("ucd-snmp/memory", "swdevt[%d]: %d\n", i,
412 swdevt[i].sw_enable));
413 if (swdevt[i].sw_enable)
415 #ifdef STRUCT_SWDEVT_HAS_SW_NBLKSENABLED
416 DEBUGMSGTL(("ucd-snmp/memory",
417 " swdevt.sw_nblksenabled: %d\n",
418 swdevt[i].sw_nblksenabled));
419 spacetotal += swdevt[i].sw_nblksenabled;
421 DEBUGMSGTL(("ucd-snmp/memory", " swdevt.sw_nblks: %d\n",
422 swdevt[i].sw_nblks));
423 spacetotal += swdevt[i].sw_nblks;
425 DEBUGMSGTL(("ucd-snmp/memory", " swdevt.sw_nfpgs: %d\n",
426 swdevt[i].sw_nfpgs));
427 spaceleft += (swdevt[i].sw_nfpgs * 4);
431 (FSWDEVT_SYMBOL, (char *) fswdevt,
432 sizeof(struct fswdevt) * nswapfs)
435 DEBUGMSGTL(("ucd-snmp/memory", "%d fs swap devices: \n", nswapfs));
436 for (i = 0; i < nswapfs; i++) {
437 DEBUGMSGTL(("ucd-snmp/memory", "fswdevt[%d]: %d\n", i,
438 fswdevt[i].fsw_enable));
439 if (fswdevt[i].fsw_enable)
441 spacetotal += (fswdevt[i].fsw_limit * 2048); /* 2048=bytes per page? */
442 spaceleft += (fswdevt[i].fsw_limit * 2048 -
443 ((fswdevt[i].fsw_allocated -
444 fswdevt[i].fsw_min) * 37));
445 DEBUGMSGTL(("ucd-snmp/memory",
446 " fswdevt[i].fsw_limit: %d\n",
447 fswdevt[i].fsw_limit));
448 DEBUGMSGTL(("ucd-snmp/memory",
449 " fswdevt[i].fsw_allocated: %d\n",
450 fswdevt[i].fsw_allocated));
451 DEBUGMSGTL(("ucd-snmp/memory",
452 " fswdevt[i].fsw_min: %d\n",
453 fswdevt[i].fsw_min));
454 DEBUGMSGTL(("ucd-snmp/memory",
455 " fswdevt[i].fsw_reserve: %d\n",
456 fswdevt[i].fsw_reserve));
458 * 37 = calculated value I know it makes no sense, nor is it accurate
463 * this is a real hack. I need to get the hold info from swapinfo, but
464 * I can't figure out how to read it out of the kernel directly
467 strcpy(ex.command, "/etc/swapinfo -h");
468 if ((fd = get_exec_output(&ex)) != -1) {
469 file = fdopen(fd, "r");
471 i <= 2 && fgets(ex.output, sizeof(ex.output), file) != NULL;
473 if (fgets(ex.output, sizeof(ex.output), file) != NULL) {
474 cp = skip_white(ex.output); /* not there should be any */
475 cp = skip_not_white(cp); /* skip over "reserve" */
477 cp = skip_not_white(cp); /* avail swap, a '-' in most cases */
479 spaceleft -= atoi(cp); /* reserved swap */
486 #endif /* !linux && !bsdi2 && !hpux10 && !hpux11 */
499 var_extensible_mem(struct variable *vp,
503 size_t * var_len, WriteMethod ** write_method)
506 static long long_ret;
507 static char errmsg[300];
509 #if defined(hpux10) || defined(hpux11)
510 struct pst_dynamic pst_buf;
511 #elif defined(TOTAL_MEMORY_SYMBOL) || defined(USE_SYSCTL_VM)
512 struct vmtotal total;
516 long_ret = 0; /* set to 0 as default */
518 if (header_generic(vp, name, length, exact, var_len, write_method))
522 #if defined(hpux10) || defined(hpux11)
523 if (pstat_getdynamic(&pst_buf, sizeof(struct pst_dynamic), 1, 0) < 0)
525 #elif defined(USE_SYSCTL_VM)
527 * sum memory statistics
530 size_t size = sizeof(total);
531 static int mib[] = { CTL_VM, VM_TOTAL };
532 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0)
535 #elif defined(TOTAL_MEMORY_SYMBOL)
536 if (auto_nlist(TOTAL_MEMORY_SYMBOL, (char *) &total, sizeof(total)) ==
545 return ((u_char *) (&long_ret));
546 case ERRORNAME: /* dummy name */
547 sprintf(errmsg, "swap");
548 *var_len = strlen(errmsg);
549 return ((u_char *) (errmsg));
551 long_ret = getswap(SWAPGETTOTAL);
552 return ((u_char *) (&long_ret));
554 long_ret = getswap(SWAPGETLEFT);
555 return ((u_char *) (&long_ret));
557 long_ret = minimumswap;
558 return ((u_char *) (&long_ret));
560 #if defined(USE_SYSCTL)
562 size_t size = sizeof(long_ret);
563 static int mib[] = { CTL_HW, HW_PHYSMEM };
564 if (sysctl(mib, 2, &long_ret, &size, NULL, 0) < 0)
566 long_ret = long_ret / 1024;
568 #elif defined(hpux10) || defined(hpux11)
570 struct pst_static pst_buf;
571 if (pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0)
575 pst_buf.physical_memory * (pst_buf.page_size / 1024);
578 long_ret = memory(meminfo_total);
579 #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
581 sysconf(_SC_PHYS_PAGES) * (sysconf(_SC_PAGESIZE) / 1024);
582 #elif defined(PHYSMEM_SYMBOL)
586 (PHYSMEM_SYMBOL, (char *) &result, sizeof(result)) == 0)
588 long_ret = result * 1000; /* ??? */
591 return NULL; /* no dummy values */
593 return ((u_char *) (&long_ret));
596 long_ret = memory(meminfo_free);
597 #elif defined(hpux10) || defined(hpux11)
598 long_ret = pagetok((int) pst_buf.psd_arm);
599 #elif defined(TOTAL_MEMORY_SYMBOL) || defined(USE_SYSCTL_VM)
600 long_ret = pagetok((int) total.t_arm);
602 return NULL; /* no dummy values */
604 return ((u_char *) (&long_ret));
606 case MEMTOTALSWAPTXT:
607 #if defined(hpux10) || defined(hpux11)
608 long_ret = pagetok((int) pst_buf.psd_vmtxt);
609 #elif !defined(bsdi2)
610 long_ret = pagetok(total.t_vmtxt);
612 return NULL; /* no dummy values */
614 return ((u_char *) (&long_ret));
616 #if defined(hpux10) || defined(hpux11)
617 long_ret = pagetok((int) pst_buf.psd_avmtxt);
618 #elif !defined(bsdi2)
619 long_ret = pagetok(total.t_avmtxt);
621 return NULL; /* no dummy values */
623 return ((u_char *) (&long_ret));
624 case MEMTOTALREALTXT:
625 #if defined(hpux10) || defined(hpux11)
626 long_ret = pagetok((int) pst_buf.psd_rmtxt);
627 #elif !defined(bsdi2)
628 long_ret = pagetok(total.t_rmtxt);
630 return NULL; /* no dummy values */
632 return ((u_char *) (&long_ret));
634 #if defined(hpux10) || defined(hpux11)
635 long_ret = pagetok((int) pst_buf.psd_armtxt);
636 #elif !defined(bsdi2)
637 long_ret = pagetok(total.t_armtxt);
639 return NULL; /* no dummy values */
641 return ((u_char *) (&long_ret));
645 long_ret = memory(meminfo_free) + memswap(meminfo_free);
646 #elif defined(hpux10) || defined(hpux11)
647 long_ret = pagetok((int) pst_buf.psd_free);
649 long_ret = pagetok(total.t_free);
651 return ((u_char *) (&long_ret));
654 long_ret = memory(meminfo_cached);
656 return NULL; /* no dummy values */
658 return ((u_char *) (&long_ret));
661 long_ret = memory(meminfo_buffers);
663 return NULL; /* no dummy values */
665 return ((u_char *) (&long_ret));
668 long_ret = memory(meminfo_shared);
670 return NULL; /* no dummy values */
672 return ((u_char *) (&long_ret));
674 long_ret = getswap(SWAPGETLEFT);
675 long_ret = (long_ret > minimumswap) ? 0 : 1;
676 return ((u_char *) (&long_ret));
678 long_ret = getswap(SWAPGETLEFT);
679 if ((long_ret > minimumswap) ? 0 : 1)
680 sprintf(errmsg, "Running out of swap space (%ld)",
681 getswap(SWAPGETLEFT));
684 *var_len = strlen(errmsg);
685 return ((u_char *) (errmsg));