diff --git a/src/uptime.c b/src/uptime.c
index f98be06587e7a1af91a8784eb7c81d52ed9b3457..064c3ceed4752a359c7ec2e5b9d84afa27068543 100644 (file)
--- a/src/uptime.c
+++ b/src/uptime.c
#include "plugin.h"
#if KERNEL_LINUX
-# define UPTIME_FILE "/proc/uptime"
-/*
- No need for includes, using /proc filesystem, Linux only.
-*/
+# define STAT_FILE "/proc/stat"
+/* Using /proc filesystem to retrieve the boot time, Linux only. */
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
-/* something to include? maybe <sys/sysinfo.h> ? */
-/*
- Using kstats chain to retrieve the boot time, this applies to:
- - Solaris / OpenSolaris
-*/
+/* Using kstats chain to retrieve the boot time on Solaris / OpenSolaris systems */
/* #endif HAVE_LIBKSTAT */
#elif HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
-/*
- Using sysctl interface to retrieve the boot time, this applies to:
- - *BSD
- - Darwin / OS X
-*/
+/* Using sysctl interface to retrieve the boot time on *BSD / Darwin / OS X systems */
/* #endif HAVE_SYS_SYSCTL_H */
+#elif HAVE_PERFSTAT
+# include <sys/protosw.h>
+# include <libperfstat.h>
+/* Using perfstat_cpu_total to retrive the boot time in AIX */
+/* #endif HAVE_PERFSTAT */
+
#else
# error "No applicable input method."
#endif
-
-#if !KERNEL_LINUX
-#define INIT_FAILED "uptime plugin: unable to calculate uptime, the plugin will be disabled."
-#endif
-
-
-#if KERNEL_LINUX
-/* global variables not needed*/
-
-#elif HAVE_SYS_SYSCTL_H || HAVE_LIBKSTAT
+/*
+ * Global variables
+ */
+/* boottime always used, no OS distinction */
static time_t boottime;
-# if HAVE_LIBKSTAT
-extern kstat_ctl_t *kc;
-# endif
-
-#endif
+#if HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
+#endif /* #endif HAVE_LIBKSTAT */
static void uptime_submit (gauge_t uptime)
{
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "uptime", sizeof (vl.plugin));
plugin_dispatch_values (&vl);
}
-#if !KERNEL_LINUX
-static int uptime_init (void)
+static int uptime_init (void) /* {{{ */
{
-/* NOTE
+ /*
+ * On most unix systems the uptime is calculated by looking at the boot
+ * time (stored in unix time, since epoch) and the current one. We are
+ * going to do the same, reading the boot time value while executing
+ * the uptime_init function (there is no need to read, every time the
+ * plugin_read is called, a value that won't change). However, since
+ * uptime_init is run only once, if the function fails in retrieving
+ * the boot time, the plugin is unregistered and there is no chance to
+ * try again later. Nevertheless, this is very unlikely to happen.
+ */
+
+#if KERNEL_LINUX
+ unsigned long starttime;
+ char buffer[1024];
+ int ret;
+ FILE *fh;
+
+ ret = 0;
+
+ fh = fopen (STAT_FILE, "r");
+
+ if (fh == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("uptime plugin: Cannot open "STAT_FILE": %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
- On unix systems other than Linux there is no /proc filesystem which
- calculates the uptime every time we call a read for the /proc/uptime
- file, the only information available is the boot time (in unix time,
- since epoch). Hence there is no need to read, every time the
- plugin_read is called, a value that won't change: this is a right
- task for the uptime_init function. However, since uptime_init is run
- only once, if the function fails in retrieving the boot time, the
- plugin is unregistered and there is no chance to try again later.
- Nevertheless, this is very unlikely to happen.
+ while (fgets (buffer, 1024, fh) != NULL)
+ {
+ /* look for the btime string and read the value */
+ ret = sscanf (buffer, "btime %lu", &starttime);
+ /* avoid further loops if btime has been found and read
+ * correctly (hopefully) */
+ if (ret == 1)
+ break;
+ }
+
+ fclose (fh);
+
+ /* loop done, check if no value has been found/read */
+ if (ret != 1)
+ {
+ ERROR ("uptime plugin: No value read from "STAT_FILE"");
+ return (-1);
+ }
-*/
+ boottime = (time_t) starttime;
-# if HAVE_LIBKSTAT
+ if (boottime == 0)
+ {
+ ERROR ("uptime plugin: btime read from "STAT_FILE", "
+ "but `boottime' is zero!");
+ return (-1);
+ }
+/* #endif KERNEL_LINUX */
+#elif HAVE_LIBKSTAT
kstat_t *ksp;
kstat_named_t *knp;
ksp = NULL;
knp = NULL;
- /* kstats chain already opened by update_kstat (using *kc), let's verify everything went fine. */
- if ( kc == NULL )
+ /* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */
+ if (kc == NULL)
+ {
+ ERROR ("uptime plugin: kstat chain control structure not available.");
+ return (-1);
+ }
+
+ ksp = kstat_lookup (kc, "unix", 0, "system_misc");
+ if (ksp == NULL)
{
- ERROR ("uptime plugin: unable to open kstat control structure");
- ERROR (INIT_FAILED);
+ ERROR ("uptime plugin: Cannot find unix:0:system_misc kstat.");
return (-1);
}
- if (( ksp = kstat_lookup (kc, "unix", 0, "system_misc")) == NULL )
+ if (kstat_read (kc, ksp, NULL) < 0)
{
- ERROR ("uptime plugin: cannot find %s kstat", "unix:0:system_misc");
- ERROR (INIT_FAILED);
+ ERROR ("uptime plugin: kstat_read failed.");
return (-1);
}
- if (( kstat_read (kc, ksp, NULL) < 0 ) ||
- (( knp = (kstat_named_t *) kstat_data_lookup (ksp, "boot_time")) != NULL ))
+ knp = (kstat_named_t *) kstat_data_lookup (ksp, "boot_time");
+ if (knp == NULL)
{
- ERROR ("uptime plugin: kstat data reading failed");
- ERROR (INIT_FAILED);
+ ERROR ("uptime plugin: kstat_data_lookup (boot_time) failed.");
return (-1);
}
boottime = (time_t) knp->value.ui32;
+ if (boottime == 0)
+ {
+ ERROR ("uptime plugin: kstat_data_lookup returned success, "
+ "but `boottime' is zero!");
+ return (-1);
+ }
/* #endif HAVE_LIBKSTAT */
# elif HAVE_SYS_SYSCTL_H
-
struct timeval boottv;
size_t boottv_len;
+ int status;
- int mib[2];
+ int mib[2];
- mib[0] = CTL_KERN;
- mib[1] = KERN_BOOTTIME;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
- boottv_len = sizeof (boottv);
+ boottv_len = sizeof (boottv);
+ memset (&boottv, 0, boottv_len);
- if (( sysctl (mib, 2, &boottv, &boottv_len, NULL, 0) != 0 ) || boottv.tv_sec == 0 )
- {
- char errbuf[1024];
- ERROR ("uptime plugin: no value read from sysctl interface: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- ERROR (INIT_FAILED);
- return (-1);
- }
+ status = sysctl (mib, STATIC_ARRAY_SIZE (mib), &boottv, &boottv_len,
+ /* new_value = */ NULL, /* new_length = */ 0);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("uptime plugin: No value read from sysctl interface: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
boottime = boottv.tv_sec;
+ if (boottime == 0)
+ {
+ ERROR ("uptime plugin: sysctl(3) returned success, "
+ "but `boottime' is zero!");
+ return (-1);
+ }
/* #endif HAVE_SYS_SYSCTL_H */
-# endif
-
- return (0);
-
-}
-#endif
+#elif HAVE_PERFSTAT
+ int status;
+ perfstat_cpu_total_t cputotal;
+ int hertz;
-static int uptime_read (void)
-{
- gauge_t uptime;
-
-#if KERNEL_LINUX
-
- FILE *fh;
-
- fh = fopen (UPTIME_FILE, "r");
-
- if (fh == NULL)
+ status = perfstat_cpu_total(NULL, &cputotal,
+ sizeof(perfstat_cpu_total_t), 1);
+ if (status < 0)
{
char errbuf[1024];
- ERROR ("uptime plugin: cannot open %s: %s", UPTIME_FILE,
+ ERROR ("uptime plugin: perfstat_cpu_total: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
- if ( fscanf (fh, "%lf", &uptime) < 1 )
- {
- WARNING ("no value read from %s", UPTIME_FILE);
- fclose (fh);
- return (-1);
- }
+ hertz = sysconf(_SC_CLK_TCK);
+ if (hertz <= 0)
+ hertz = HZ;
- fclose (fh);
-
-/* #endif KERNEL_LINUX */
+ boottime = time(NULL) - cputotal.lbolt / hertz;
+#endif /* HAVE_PERFSTAT */
+ return (0);
+} /* }}} int uptime_init */
-#elif HAVE_SYS_SYSCTL_H || HAVE_LIBKSTAT
-
+static int uptime_read (void)
+{
+ gauge_t uptime;
time_t elapsed;
+ /* calculate the ammount of time elapsed since boot, AKA uptime */
elapsed = time (NULL) - boottime;
uptime = (gauge_t) elapsed;
-/* #endif HAVE_SYS_SYSCTL_H */
-
-#endif
-
uptime_submit (uptime);
return (0);
void module_register (void)
{
-#if !KERNEL_LINUX
plugin_register_init ("uptime", uptime_init);
-#endif
plugin_register_read ("uptime", uptime_read);
} /* void module_register */