500-fix-uptime-reading.patch 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. From af01dd6fa3eb458e2fbb272703b0cae37ea54a9b Mon Sep 17 00:00:00 2001
  2. From: Marcin Jurkowski <marcin1j@gmail.com>
  3. Date: Tue, 11 Jul 2017 15:00:25 +0200
  4. Subject: [PATCH] uptime plugin: don't cache boot time and simplify Linux code
  5. Caching boottime on startup yields incorrect uptime values if system
  6. date changes after the daemon is started.
  7. This is almost certain to happen on embedded systems without RTC, where
  8. clock is set from NTP server at some point after boot process.
  9. On Linux, we can retrieve uptime directly by either reading /proc/uptime
  10. (it's sufficient to read a few bytes) or calling sysinfo() function.
  11. Use the latter since it's the most efficient way in speed, memory
  12. requirements and code simplicity terms.
  13. --- a/src/uptime.c
  14. +++ b/src/uptime.c
  15. @@ -24,8 +24,7 @@
  16. #include "plugin.h"
  17. #if KERNEL_LINUX
  18. -# define STAT_FILE "/proc/stat"
  19. -/* Using /proc filesystem to retrieve the boot time, Linux only. */
  20. +#include <sys/sysinfo.h>
  21. /* #endif KERNEL_LINUX */
  22. #elif HAVE_LIBKSTAT
  23. @@ -50,8 +49,6 @@
  24. /*
  25. * Global variables
  26. */
  27. -/* boottime always used, no OS distinction */
  28. -static time_t boottime;
  29. #if HAVE_LIBKSTAT
  30. extern kstat_ctl_t *kc;
  31. @@ -74,8 +71,6 @@ static void uptime_submit (gauge_t uptim
  32. plugin_dispatch_values (&vl);
  33. }
  34. -static int uptime_init (void) /* {{{ */
  35. -{
  36. /*
  37. * On most unix systems the uptime is calculated by looking at the boot
  38. * time (stored in unix time, since epoch) and the current one. We are
  39. @@ -86,52 +81,21 @@ static int uptime_init (void) /* {{{ */
  40. * the boot time, the plugin is unregistered and there is no chance to
  41. * try again later. Nevertheless, this is very unlikely to happen.
  42. */
  43. -
  44. +static time_t uptime_get_sys(void) { /* {{{ */
  45. + time_t result;
  46. #if KERNEL_LINUX
  47. - unsigned long starttime;
  48. - char buffer[1024];
  49. - int ret;
  50. - FILE *fh;
  51. -
  52. - ret = 0;
  53. -
  54. - fh = fopen (STAT_FILE, "r");
  55. + struct sysinfo info;
  56. + int status;
  57. - if (fh == NULL)
  58. - {
  59. + status = sysinfo(&info);
  60. + if (status != 0) {
  61. char errbuf[1024];
  62. - ERROR ("uptime plugin: Cannot open "STAT_FILE": %s",
  63. + ERROR ("uptime plugin: Error calling sysinfo: %s",
  64. sstrerror (errno, errbuf, sizeof (errbuf)));
  65. return (-1);
  66. }
  67. - while (fgets (buffer, 1024, fh) != NULL)
  68. - {
  69. - /* look for the btime string and read the value */
  70. - ret = sscanf (buffer, "btime %lu", &starttime);
  71. - /* avoid further loops if btime has been found and read
  72. - * correctly (hopefully) */
  73. - if (ret == 1)
  74. - break;
  75. - }
  76. -
  77. - fclose (fh);
  78. -
  79. - /* loop done, check if no value has been found/read */
  80. - if (ret != 1)
  81. - {
  82. - ERROR ("uptime plugin: No value read from "STAT_FILE"");
  83. - return (-1);
  84. - }
  85. -
  86. - boottime = (time_t) starttime;
  87. -
  88. - if (boottime == 0)
  89. - {
  90. - ERROR ("uptime plugin: btime read from "STAT_FILE", "
  91. - "but `boottime' is zero!");
  92. - return (-1);
  93. - }
  94. + result = (time_t)info.uptime;
  95. /* #endif KERNEL_LINUX */
  96. #elif HAVE_LIBKSTAT
  97. @@ -168,14 +132,13 @@ static int uptime_init (void) /* {{{ */
  98. return (-1);
  99. }
  100. - boottime = (time_t) knp->value.ui32;
  101. -
  102. - if (boottime == 0)
  103. - {
  104. + if (knp->value.ui32 == 0) {
  105. ERROR ("uptime plugin: kstat_data_lookup returned success, "
  106. "but `boottime' is zero!");
  107. return (-1);
  108. }
  109. +
  110. + result = time(NULL) - (time_t)knp->value.ui32;
  111. /* #endif HAVE_LIBKSTAT */
  112. # elif HAVE_SYS_SYSCTL_H
  113. @@ -201,14 +164,13 @@ static int uptime_init (void) /* {{{ */
  114. return (-1);
  115. }
  116. - boottime = boottv.tv_sec;
  117. -
  118. - if (boottime == 0)
  119. - {
  120. + if (boottv.tv_sec == 0) {
  121. ERROR ("uptime plugin: sysctl(3) returned success, "
  122. "but `boottime' is zero!");
  123. return (-1);
  124. }
  125. +
  126. + result = time(NULL) - boottv.tv_sec;
  127. /* #endif HAVE_SYS_SYSCTL_H */
  128. #elif HAVE_PERFSTAT
  129. @@ -230,11 +192,11 @@ static int uptime_init (void) /* {{{ */
  130. if (hertz <= 0)
  131. hertz = HZ;
  132. - boottime = time(NULL) - cputotal.lbolt / hertz;
  133. + result = cputotal.lbolt / hertz;
  134. #endif /* HAVE_PERFSTAT */
  135. - return (0);
  136. -} /* }}} int uptime_init */
  137. + return result;
  138. +} /* }}} int uptime_get_sys */
  139. static int uptime_read (void)
  140. {
  141. @@ -242,7 +204,7 @@ static int uptime_read (void)
  142. time_t elapsed;
  143. /* calculate the amount of time elapsed since boot, AKA uptime */
  144. - elapsed = time (NULL) - boottime;
  145. + elapsed = uptime_get_sys();
  146. uptime = (gauge_t) elapsed;
  147. @@ -253,6 +215,5 @@ static int uptime_read (void)
  148. void module_register (void)
  149. {
  150. - plugin_register_init ("uptime", uptime_init);
  151. plugin_register_read ("uptime", uptime_read);
  152. } /* void module_register */