X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fuptime.c;h=345128da62f6750d30655d74a3f35a841ec6a110;hb=79d834024d69d3b33e0fc4717b6560385b54cdd1;hp=f98be06587e7a1af91a8784eb7c81d52ed9b3457;hpb=0c3fcab4abed820084393e64dc30a88512941de1;p=collectd.git diff --git a/src/uptime.c b/src/uptime.c index f98be065..345128da 100644 --- a/src/uptime.c +++ b/src/uptime.c @@ -24,50 +24,38 @@ #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 ? */ -/* - 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 -/* - 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 +# include +/* 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) { @@ -78,7 +66,6 @@ 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)); @@ -87,132 +74,178 @@ static void uptime_submit (gauge_t uptime) 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 amount 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); @@ -220,8 +253,6 @@ static int uptime_read (void) void module_register (void) { -#if !KERNEL_LINUX plugin_register_init ("uptime", uptime_init); -#endif plugin_register_read ("uptime", uptime_read); } /* void module_register */