settimeofday() portability in hwclock

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 Hi William,

 please, review this patch. It seems we need to somehow hide libc
 maintainers' creativity as settimeofday() have different behavior on
 different libcs ;-) For example musl-C completely ignores TZ.

 I'd like to keep the current structure of our code (IMHO it's pretty
 readable now), so I have  introduced  __set_time() and __set_timezone()
 to hide the portability issues.

    Karel

>From 8a1e6fe5c37e2122264c501d5452a5b55ae33b66 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@xxxxxxxxxx>
Date: Mon, 11 May 2020 13:35:21 +0200
Subject: [PATCH] hwclock: improve use of settimeofday() portability

The different libc implements TZ deprecation in settimeofday() library
function in the different way. Let's hide these portability issues and
use directly Linux syscall to set timezone.

Addresses: https://github.com/karelzak/util-linux/issues/995
Signed-off-by: Karel Zak <kzak@xxxxxxxxxx>
---
 sys-utils/hwclock.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
index 37abab42d..ac4f9c753 100644
--- a/sys-utils/hwclock.c
+++ b/sys-utils/hwclock.c
@@ -71,6 +71,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/syscall.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -655,7 +656,6 @@ display_time(struct timeval hwctime)
  * ptr2utc: tz.tz_minuteswest is zero (UTC).
  * PCIL: persistent_clock_is_local, sets the "11 minute mode" timescale.
  * firsttime: locks the warp_clock function (initialized to 1 at boot).
- * Since glibc v2.31 settimeofday() will fail if both args are non NULL
  *
  * +---------------------------------------------------------------------------+
  * |  op     | RTC scale | settimeofday calls                                  |
@@ -666,7 +666,25 @@ display_time(struct timeval hwctime)
  * | hctosys |   UTC     | 1st) locks warp* 2nd) sets tz 3rd) sets system time |
  * +---------------------------------------------------------------------------+
  *                         * only on first call after boot
+ *
+ * POSIX 2008 marked TZ in settimeofday() as deprecated. Unfortunately,
+ * different C libraries react to this deprecation in a different way. Since
+ * glibc v2.31 settimeofday() will fail if both args are not NULL, Musl-C
+ * ignores TZ at all, etc. We use __set_time() and __set_timezone() to hide
+ * these portability issues and to keep code readable.
  */
+#define __set_time(_tv)		settimeofday(_tv, NULL)
+
+static inline int __set_timezone(const struct timezone *tz)
+{
+#ifdef SYS_settimeofday
+	errno = 0;
+	return syscall(SYS_settimeofday, NULL, tz);
+#else
+	return settimeofday(NULL, tz);
+#endif
+}
+
 static int
 set_system_clock(const struct hwclock_control *ctl,
 		 const struct timeval newtime)
@@ -703,15 +721,15 @@ set_system_clock(const struct hwclock_control *ctl,
 
 		/* If UTC RTC: lock warp_clock and PCIL */
 		if (ctl->universal)
-			rc = settimeofday(NULL, &tz_utc);
+			rc = __set_timezone(&tz_utc);
 
 		/* Set kernel tz; if localtime RTC: warp_clock and set PCIL */
 		if (!rc && !( ctl->universal && !minuteswest ))
-			rc = settimeofday(NULL, &tz);
+			rc = __set_timezone(&tz);
 
 		/* Set the System Clock */
 		if ((!rc || errno == ENOSYS) && ctl->hctosys)
-			rc = settimeofday(&newtime, NULL);
+			rc = __set_time(&newtime);
 
 		if (rc) {
 			warn(_("settimeofday() failed"));
-- 
2.25.4




[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux