diff --git a/src/util/virhostuptime.c b/src/util/virhostuptime.c index 62b781acd5..3189074d3d 100644 --- a/src/util/virhostuptime.c +++ b/src/util/virhostuptime.c @@ -25,16 +25,68 @@ #endif #include "virhostuptime.h" +#include "viralloc.h" +#include "virfile.h" +#include "virlog.h" +#include "virstring.h" +#include "virtime.h" #include "virthread.h" +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.virhostuptime"); + static unsigned long long bootTime; static int bootTimeErrno; static virOnceControl virHostGetBootTimeOnce = VIR_ONCE_CONTROL_INITIALIZER; -#ifdef HAVE_GETUTXID +#if defined(__linux__) +# define UPTIME_FILE "/proc/uptime" +static int +virHostGetBootTimeProcfs(unsigned long long *btime) +{ + unsigned long long now; + double up; + VIR_AUTOFREE (char *buf) = NULL; + char *tmp; + + if (virTimeMillisNow(&now) < 0) + return -errno; + + /* 1KiB limit is more than enough. */ + if (virFileReadAll(UPTIME_FILE, 1024, &buf) < 0) + return -errno; + + /* buf contains two doubles now: + * $uptime $idle_time + * We're interested only in the first one */ + if (!(tmp = strchr(buf, ' '))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("uptime file has unexpected format '%s'"), + buf); + return -EINVAL; + } + + *tmp = '\0'; + + if (virStrToDouble(buf, NULL, &up) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse sched info value '%s'"), + buf); + return -EINVAL; + } + + *btime = now / 1000 - up + 0.5; + + return 0; +} +#endif /* defined(__linux__) */ + +#if defined(HAVE_GETUTXID) || defined(__linux__) static void virHostGetBootTimeOnceInit(void) { +# ifdef HAVE_GETUTXID struct utmpx id = {.ut_type = BOOT_TIME}; struct utmpx *res = NULL; @@ -45,16 +97,21 @@ } endutxent(); +# endif /* HAVE_GETUTXID */ + + if (bootTimeErrno != 0 || bootTimeErrno == 0) { + bootTimeErrno = -virHostGetBootTimeProcfs(&bootTime); + } } -#else /* !HAVE_GETUTXID */ +#else /* !defined(HAVE_GETUTXID) && !defined(__linux__) */ static void virHostGetBootTimeOnceInit(void) { bootTimeErrno = ENOSYS; } -#endif /* HAVE_GETUTXID */ +#endif /* !defined(HAVE_GETUTXID) && !defined(__linux__) */ /** * virHostGetBootTime: --