I'd like to propose that gmond.c be modifed such that metric_init is
called before become_a_nobody drops privs.  This change plus a rewrite
of gmond/machines/freebsd.c allows FreeBSD to preopen /dev/kmem and
leave a handle to it which should increase efficency and allow gmond to
run reliably on FreeBSD with lowered privleges.  The changes I've made
are below.

The patch uses libkvm on FreeBSD 4.x and switches to the unprivleged
vm.swap_info sysctl if available (5.0+).

I've been running this patch for quite some time.

-- Brooks

--- gmond/gmond.c.orig  Tue Jan  7 09:05:04 2003
+++ gmond/gmond.c       Thu Apr  3 16:40:22 2003
@@ -163,6 +163,13 @@
    print_gmond_config();
    */
 
+   /* in machine.c */
+   initval = metric_init();
+   if ( initval.int32 <0)
+      {
+         err_quit("metric_init() returned an error");
+      }
+
    if(!gmond_config.no_setuid)
       become_a_nobody(gmond_config.setuid);
 
@@ -266,13 +273,6 @@
                return -1;
             }
          debug_msg("multicasting on channel %s %d", 
gmond_config.mcast_channel, gmond_config.mcast_port);
-
-         /* in machine.c */
-         initval = metric_init();
-         if ( initval.int32 <0)
-            {
-               err_quit("monitor_init() returned an error");
-            }
 
          pthread_create(&tid, &attr, monitor_thread, NULL);
          debug_msg("created monitor thread");


--- gmond/machines/freebsd.c.orig       Thu Aug 15 10:17:25 2002
+++ gmond/machines/freebsd.c    Wed May 28 12:51:18 2003
@@ -10,11 +10,36 @@
 #include <sys/param.h> 
 #include <sys/sysctl.h>
 #include <sys/user.h>
+#if __FreeBSD_version < 500101
 #include <sys/dkstat.h>
+#else
+#include <sys/resource.h>
+#endif
+#include <sys/stat.h>
+#include <vm/vm_param.h>
 #include <unistd.h>
 #include "ganglia.h"
 #include "metric_typedefs.h"
 
+#define MIB_SWAPINFO_SIZE 3
+
+#ifndef XSWDEV_VERSION
+#define XSWDEV_VERSION  1
+struct xswdev {
+        u_int   xsw_version;
+        udev_t  xsw_dev;
+        int     xsw_flags;
+        int     xsw_nblks;
+        int     xsw_used;
+};
+#endif
+
+static int use_vm_swap_info = 0;
+static int mibswap[MIB_SWAPINFO_SIZE];
+static size_t mibswap_size;
+static kvm_t *kd = NULL;
+static int pagesize;
+
 /* Function prototypes */
 long percentages(int cnt, int *out, register long *new,
                           register long *old, long *diffs);
@@ -27,6 +52,19 @@
 metric_init(void)
 {
    g_val_t val;
+
+   /*
+    * Try to use the vm.swap_info sysctl to gather swap data.  If it
+    * isn't implemented, fall back to trying to old kvm based interface.
+    */
+   mibswap_size = MIB_SWAPINFO_SIZE;
+   if (sysctlnametomib("vm.swap_info", mibswap, &mibswap_size) == -1) {
+      kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "metric_init()"); 
+   } else {
+      use_vm_swap_info = 1;
+   }
+   pagesize = getpagesize();
+
    val.int32 = SYNAPSE_SUCCESS;
    return val;
 }
@@ -81,21 +119,33 @@
 swap_total_func ( void )
 {
    g_val_t val;
-
    struct kvm_swap swap[1];
-   kvm_t *kd;
+   struct xswdev xsw;
+   size_t mibsize, size;
    int totswap, n;
 
-   kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open"); 
-   n = kvm_getswapinfo(kd, swap, 1, 0);
-   if (n < 0 || swap[0].ksw_total == 0) { 
-       val.uint32 = 0;
+   val.uint32 = 0; 
+   totswap = 0;
+
+   if (use_vm_swap_info) {
+      for (n = 0; ; ++n) {
+        mibswap[mibswap_size] = n;
+        size = sizeof(xsw);
+        if (sysctl(mibswap, mibswap_size + 1, &xsw, &size, NULL, NULL) == -1)
+           break;
+        if (xsw.xsw_version != XSWDEV_VERSION)
+           return val;
+         totswap += xsw.xsw_nblks;
+       }
+   } else if(kd != NULL) {
+      n = kvm_getswapinfo(kd, swap, 1, 0);
+      if (n < 0 || swap[0].ksw_total == 0) { 
+         val.uint32 = 0;
+      }
+      totswap = swap[0].ksw_total;
    }
-   totswap = swap[0].ksw_total;
-   totswap *= getpagesize() / 1024;
-   val.uint32 = totswap;
-   kvm_close(kd);
 
+   val.uint32 = totswap * (pagesize / 1024);
    return val;
 }
 
@@ -330,9 +380,8 @@
    len = sizeof (free_pages);
    if((sysctlbyname("vm.stats.vm.v_free_count", &free_pages, &len, NULL, 0) 
        == -1) || !len) free_pages = 0; 
-   free_pages *= getpagesize() / 1024;
 
-   val.uint32 = free_pages;
+   val.uint32 = free_pages * (pagesize / 1024);
    return val;
 }
 
@@ -373,9 +422,7 @@
        || !len)
       cache = 0; 
 
-   cache *= getpagesize() / 1024;
-
-   val.uint32 = cache;
+   val.uint32 = cache * (pagesize / 1024);
    return val;
 }
 
@@ -383,23 +430,35 @@
 swap_free_func ( void )
 {
    g_val_t val;
+
    struct kvm_swap swap[1];
-   kvm_t *kd;
+   struct xswdev xsw;
+   size_t size;
    int totswap, usedswap, freeswap, n;
 
-   kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open");
-   n = kvm_getswapinfo(kd, swap, 1, 0);
-   if (n < 0 || swap[0].ksw_total == 0) {
-       val.uint32 = 0;
-   }
-   totswap = swap[0].ksw_total;
-   usedswap = swap[0].ksw_used;
-   kvm_close(kd);
+   val.uint32 = 0;
+   totswap = 0;
+   usedswap = 0;
 
-   freeswap = totswap-usedswap;
-   freeswap *= getpagesize() / 1024;
+   if (use_vm_swap_info) {
+      for (n = 0; ; ++n) {
+        mibswap[mibswap_size] = n;
+        size = sizeof(xsw);
+        if (sysctl(mibswap, mibswap_size + 1, &xsw, &size, NULL, NULL) == -1)
+           break;
+        if (xsw.xsw_version != XSWDEV_VERSION)
+           return val;
+         totswap += xsw.xsw_nblks;
+         usedswap += xsw.xsw_used;
+       }
+   } else if(kd != NULL) { 
+      n = kvm_getswapinfo(kd, swap, 1, 0);
+      totswap = swap[0].ksw_total;
+      usedswap = swap[0].ksw_used;
+   }
+   freeswap = totswap - usedswap;
 
-   val.uint32 = freeswap;
+   val.uint32 = freeswap * (pagesize / 1024);
    return val;
 }
 
-- 
Any statement of the form "X is the one, true Y" is FALSE.
PGP fingerprint 655D 519C 26A7 82E7 2529  9BF0 5D8E 8BE9 F238 1AD4

Attachment: pgpv5ONRSOEVS.pgp
Description: PGP signature

Reply via email to