Util-Linux package development
 help / color / mirror / Atom feed
From: Karel Zak <kzak@redhat.com>
To: J William Piggott <elseifthen@gmx.com>
Cc: util-linux@vger.kernel.org
Subject: review - hwclock: fix for glibc 2.31 settimeofday()
Date: Wed, 19 Feb 2020 16:30:21 +0100	[thread overview]
Message-ID: <20200219153021.47tbre7bloztmfdk@ws.net.home> (raw)


 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@redhat.com>
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@gmx.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 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@redhat.com>
 http://karelzak.blogspot.com


                 reply	other threads:[~2020-02-19 15:30 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200219153021.47tbre7bloztmfdk@ws.net.home \
    --to=kzak@redhat.com \
    --cc=elseifthen@gmx.com \
    --cc=util-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox