summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d6584e8)
raw | patch | inline | side by side (parent: d6584e8)
author | Marcin Jurkowski <marcin1j@gmail.com> | |
Tue, 11 Jul 2017 13:00:25 +0000 (15:00 +0200) | ||
committer | Marcin Jurkowski <marcin1j@gmail.com> | |
Mon, 25 Sep 2017 10:18:51 +0000 (12:18 +0200) |
Caching boottime on startup yields incorrect uptime values if system
date changes after the daemon is started.
This is almost certain to happen on embedded systems without RTC, where
clock is set from NTP server at some point after boot process.
On Linux, we can retrieve uptime directly by either reading /proc/uptime
(it's sufficient to read a few bytes) or calling sysinfo() function.
Use the latter since it's the most efficient way in speed, memory
requirements and code simplicity terms.
date changes after the daemon is started.
This is almost certain to happen on embedded systems without RTC, where
clock is set from NTP server at some point after boot process.
On Linux, we can retrieve uptime directly by either reading /proc/uptime
(it's sufficient to read a few bytes) or calling sysinfo() function.
Use the latter since it's the most efficient way in speed, memory
requirements and code simplicity terms.
src/uptime.c | patch | blob | history |
diff --git a/src/uptime.c b/src/uptime.c
index 8b83cf9be9f7def6ebc15bec94d912f5cbe14000..d51aa391a09040229113c4accae5bb387375b897 100644 (file)
--- a/src/uptime.c
+++ b/src/uptime.c
#include "plugin.h"
#if KERNEL_LINUX
-#define UPTIME_FILE "/proc/uptime"
-/* Using /proc filesystem to retrieve the boot time, Linux only. */
+#include <sys/sysinfo.h>
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
/*
* Global variables
*/
-/* boottime always used, no OS distinction */
-static time_t boottime;
#if HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
plugin_dispatch_values(&vl);
}
-static int uptime_init(void) /* {{{ */
-{
/*
* 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
* the boot time, the plugin is unregistered and there is no chance to
* try again later. Nevertheless, this is very unlikely to happen.
*/
-
+static time_t uptime_get_sys(void) { /* {{{ */
+ time_t result;
#if KERNEL_LINUX
- FILE *fh = fopen(UPTIME_FILE, "r");
- if (fh == NULL) {
+ struct sysinfo info;
+ int status;
+
+ status = sysinfo(&info);
+ if (status != 0) {
char errbuf[1024];
- ERROR("uptime plugin: Cannot open " UPTIME_FILE ": %s",
+ ERROR("uptime plugin: Error calling sysinfo: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
return -1;
}
- double uptime_seconds = 0.0;
- if (fscanf(fh, "%lf", &uptime_seconds) != 1) {
- ERROR("uptime plugin: No value read from " UPTIME_FILE "");
- fclose(fh);
- return -1;
- }
-
- fclose(fh);
-
- if (uptime_seconds == 0.0) {
- ERROR("uptime plugin: uptime read from " UPTIME_FILE ", "
- "but it is zero!");
- return -1;
- }
-
- boottime = time(NULL) - (long)uptime_seconds;
+ result = (time_t)info.uptime;
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
return -1;
}
- boottime = (time_t)knp->value.ui32;
-
- if (boottime == 0) {
+ if (knp->value.ui32 == 0) {
ERROR("uptime plugin: kstat_data_lookup returned success, "
"but `boottime' is zero!");
return -1;
}
+
+ result = time(NULL) - (time_t)knp->value.ui32;
/* #endif HAVE_LIBKSTAT */
#elif HAVE_SYS_SYSCTL_H
return -1;
}
- boottime = boottv.tv_sec;
-
- if (boottime == 0) {
+ if (boottv.tv_sec == 0) {
ERROR("uptime plugin: sysctl(3) returned success, "
"but `boottime' is zero!");
return -1;
}
+
+ result = time(NULL) - boottv.tv_sec;
/* #endif HAVE_SYS_SYSCTL_H */
#elif HAVE_PERFSTAT
if (hertz <= 0)
hertz = HZ;
- boottime = time(NULL) - cputotal.lbolt / hertz;
+ result = cputotal.lbolt / hertz;
#endif /* HAVE_PERFSTAT */
- return 0;
-} /* }}} int uptime_init */
+ return result;
+} /* }}} int uptime_get_sys */
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;
+ elapsed = uptime_get_sys();
uptime = (gauge_t)elapsed;
}
void module_register(void) {
- plugin_register_init("uptime", uptime_init);
plugin_register_read("uptime", uptime_read);
} /* void module_register */