summary refs log tree commit diff
path: root/shared/systemd/src/basic/time-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/systemd/src/basic/time-util.c')
-rw-r--r--shared/systemd/src/basic/time-util.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
index aa790023..4411127a 100644
--- a/shared/systemd/src/basic/time-util.c
+++ b/shared/systemd/src/basic/time-util.c
@@ -6,9 +6,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/mman.h>
-#include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/timerfd.h>
 #include <sys/timex.h>
@@ -839,8 +837,12 @@ int parse_timestamp(const char *t, usec_t *usec) {
         }
         if (r == 0) {
                 bool with_tz = true;
+                char *colon_tz;
 
-                if (setenv("TZ", tz, 1) != 0) {
+                /* tzset(3) says $TZ should be prefixed with ":" if we reference timezone files */
+                colon_tz = strjoina(":", tz);
+
+                if (setenv("TZ", colon_tz, 1) != 0) {
                         shared->return_value = negative_errno();
                         _exit(EXIT_FAILURE);
                 }
@@ -1196,7 +1198,10 @@ bool ntp_synced(void) {
         if (adjtimex(&txc) < 0)
                 return false;
 
-        if (txc.status & STA_UNSYNC)
+        /* Consider the system clock synchronized if the reported maximum error is smaller than the maximum
+         * value (16 seconds). Ignore the STA_UNSYNC flag as it may have been set to prevent the kernel from
+         * touching the RTC. */
+        if (txc.maxerror >= 16000000)
                 return false;
 
         return true;
@@ -1262,6 +1267,7 @@ int get_timezones(char ***ret) {
                 }
 
                 strv_sort(zones);
+                strv_uniq(zones);
 
         } else if (errno != ENOENT)
                 return -errno;
@@ -1282,6 +1288,10 @@ bool timezone_is_valid(const char *name, int log_level) {
         if (isempty(name))
                 return false;
 
+        /* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */
+        if (streq(name, "UTC"))
+                return true;
+
         if (name[0] == '/')
                 return false;
 
@@ -1388,13 +1398,22 @@ bool clock_supported(clockid_t clock) {
 }
 
 #if 0 /* NM_IGNORED */
-int get_timezone(char **tz) {
+int get_timezone(char **ret) {
         _cleanup_free_ char *t = NULL;
         const char *e;
         char *z;
         int r;
 
         r = readlink_malloc("/etc/localtime", &t);
+        if (r == -ENOENT) {
+                /* If the symlink does not exist, assume "UTC", like glibc does*/
+                z = strdup("UTC");
+                if (!z)
+                        return -ENOMEM;
+
+                *ret = z;
+                return 0;
+        }
         if (r < 0)
                 return r; /* returns EINVAL if not a symlink */
 
@@ -1409,7 +1428,7 @@ int get_timezone(char **tz) {
         if (!z)
                 return -ENOMEM;
 
-        *tz = z;
+        *ret = z;
         return 0;
 }
 
@@ -1421,8 +1440,8 @@ struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
         return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
 }
 
-unsigned long usec_to_jiffies(usec_t u) {
-        static thread_local unsigned long hz = 0;
+static uint32_t sysconf_clock_ticks_cached(void) {
+        static thread_local uint32_t hz = 0;
         long r;
 
         if (hz == 0) {
@@ -1432,7 +1451,17 @@ unsigned long usec_to_jiffies(usec_t u) {
                 hz = r;
         }
 
-        return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
+        return hz;
+}
+
+uint32_t usec_to_jiffies(usec_t u) {
+        uint32_t hz = sysconf_clock_ticks_cached();
+        return DIV_ROUND_UP(u, USEC_PER_SEC / hz);
+}
+
+usec_t jiffies_to_usec(uint32_t j) {
+        uint32_t hz = sysconf_clock_ticks_cached();
+        return DIV_ROUND_UP(j * USEC_PER_SEC, hz);
 }
 
 usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {