review - hwclock: fix for glibc 2.31 settimeofday()

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

 



 Hi William,

please, please, review the patch below.

Let's make the review more user-friendly, all the logic is:

	if (!ctl->testing) {
		const struct timezone tz_utc = { 0 };
		const struct timezone tz = { minuteswest };

		/* warp-clock */
		if (ctl->universal)
			rc = settimeofday(NULL, &tz_utc); /* lock to UTC */
		else
			rc = settimeofday(NULL, &tz);     /* set PCIL and TZ */

		/* set timezone */
		if (!rc && ctl->universal && minuteswest)
			rc = settimeofday(NULL, &tz);

		/* set time */
		if (!rc && ctl->hctosys)
			rc = settimeofday(&newtime, NULL);

		if (rc) {
			warn(_("settimeofday() failed"));
			return  EXIT_FAILURE;
		}
	}

it means the patch splits all into three steps:
   1/ warp-clock
   2/ TZ setting (if not set in 1/)
   3/ set time

Maybe we should also ignore rc and errno==ENOSYS for
settimeofday(NULL, tz) as TZ offset modification is not supported on
some archs, but we still need to set time in this case. Not sure.

The next thing we need is to use clock_settime(CLOCK_REALTIME) to set
time and to avoid settimeofday() if possible, but it's not so
important for now.

It's like to have this glibc API change fixed in maintenance release
v2.35.2 because now hwclock -s ends with "hwclock: settimeofday()
failed: Invalid argument" after glibc update...

Thanks,
  Karel

>From c5d472cfb8b9102e4a76995228513ed6a70608e7 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@xxxxxxxxxx>
Date: Wed, 19 Feb 2020 15:50:47 +0100
Subject: [PATCH] hwclock: fix for glibc 2.31 settimeofday()

glibc announce:
  ... settimeofday can no longer be used to set the time and the offset
  simultaneously. If both of its two arguments are non-null, the call
  will fail (setting errno to EINVAL).

It means we need to call settimeofday(NULL, tz) and settimeofday(tv, NULL).

Unfortunately, settimeofday(NULL, tz) has very special warp-clock
semantic if used as the very first settimeofday() call. It means we
have to be sure that we do not touch warp-clock if we need only need
to modify system TZ. So, let's always call settimeofday(NULL, 0)
before settimeofday(NULL, tz) for UTC rtc mode when modify system TZ.

CC: J William Piggott <elseifthen@xxxxxxx>
Signed-off-by: Karel Zak <kzak@xxxxxxxxxx>
---
 sys-utils/hwclock.c | 49 ++++++++++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
index e736da717..16576bc18 100644
--- a/sys-utils/hwclock.c
+++ b/sys-utils/hwclock.c
@@ -658,6 +658,9 @@ display_time(struct timeval hwctime)
  * PCIL: persistent_clock_is_local, sets the "11 minute mode" timescale.
  * firsttime: locks the warp_clock function (initialized to 1 at boot).
  *
+ * Note that very first settimeofday(NULL, tz) modifies warp-clock as well as
+ * system TZ.
+ *
  * +---------------------------------------------------------------------------+
  * |  op     | RTC scale | settimeofday calls                                  |
  * |---------|-----------|-----------------------------------------------------|
@@ -675,41 +678,45 @@ set_system_clock(const struct hwclock_control *ctl,
 	struct tm broken;
 	int minuteswest;
 	int rc = 0;
-	const struct timezone tz_utc = { 0 };
 
 	localtime_r(&newtime.tv_sec, &broken);
 	minuteswest = -get_gmtoff(&broken) / 60;
 
 	if (ctl->verbose) {
-		if (ctl->hctosys && !ctl->universal)
-			printf(_("Calling settimeofday(NULL, %d) to set "
-				 "persistent_clock_is_local.\n"), minuteswest);
-		if (ctl->systz && ctl->universal)
+		if (ctl->universal)
 			puts(_("Calling settimeofday(NULL, 0) "
-				"to lock the warp function."));
+			       "to lock the warp function."));
+		else
+			printf(_("Calling settimeofday(NULL, %d) to set "
+				 "persistent_clock_is_local and "
+				 "the kernel timezone.\n"), minuteswest);
+
+		if (ctl->universal && minuteswest)
+			printf(_("Calling settimeofday(NULL, %d) to set "
+				 "the kernel timezone.\n"), minuteswest);
+
 		if (ctl->hctosys)
-			printf(_("Calling settimeofday(%ld.%06ld, %d)\n"),
-			       newtime.tv_sec, newtime.tv_usec, minuteswest);
-		else {
-			printf(_("Calling settimeofday(NULL, %d) "), minuteswest);
-			if (ctl->universal)
-				 puts(_("to set the kernel timezone."));
-			else
-				 puts(_("to warp System time."));
-		}
+			printf(_("Calling settimeofday(%ld.%06ld, 0) to set "
+			         "the kernel time.\n"), newtime.tv_sec, newtime.tv_usec);
 	}
 
 	if (!ctl->testing) {
+		const struct timezone tz_utc = { 0 };
 		const struct timezone tz = { minuteswest };
 
-		if (ctl->hctosys && !ctl->universal)	/* set PCIL */
+		/* warp-clock */
+		if (ctl->universal)
+			rc = settimeofday(NULL, &tz_utc); /* lock to UTC */
+		else
+			rc = settimeofday(NULL, &tz);     /* set PCIL and TZ */
+
+		/* set timezone */
+		if (!rc && ctl->universal && minuteswest)
 			rc = settimeofday(NULL, &tz);
-		if (ctl->systz && ctl->universal)	/* lock warp_clock */
-			rc = settimeofday(NULL, &tz_utc);
+
+		/* set time */
 		if (!rc && ctl->hctosys)
-			rc = settimeofday(&newtime, &tz);
-		else if (!rc)
-			rc = settimeofday(NULL, &tz);
+			rc = settimeofday(&newtime, NULL);
 
 		if (rc) {
 			warn(_("settimeofday() failed"));
-- 
2.24.1

-- 
 Karel Zak  <kzak@xxxxxxxxxx>
 http://karelzak.blogspot.com




[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