Patchwork [05/12] Use clock_settime to implement settimeofday.

login
register
mail settings
Submitter Zack Weinberg
Date Aug. 20, 2019, 1:21 p.m.
Message ID <20190820132152.24100-6-zackw@panix.com>
Download mbox | patch
Permalink /patch/34187/
State New
Headers show

Comments

Zack Weinberg - Aug. 20, 2019, 1:21 p.m.
Unconditionally, on all ports, use clock_settime to implement
settimeofday.  This is a little different from using clock_settime to
implement stime, because the vestigial “set time zone” feature of
settimeofday complicates matters.

The only remaining uses of this feature that aren’t just bugs are
using it to inform the Linux kernel of the offset between the hardware
clock and UTC, on systems where the hardware clock doesn’t run in
UTC (usually because of dual-booting with Windows).  They call
settimeofday with _only_ the timezone argument non-NULL.  Therefore,
glibc’s new behavior is: callers of settimeofday must supply one and
only one of the two arguments.  If both arguments are non-NULL, or
both arguments are NULL, the call fails and sets errno to EINVAL.

When only the timeval argument is supplied, settimeofday calls
__clock_settime(CLOCK_REALTIME), same as stime.

When only the timezone argument is supplied, settimeofday calls a new
internal function called __settimezone.  On Linux, only, this function
will pass the timezone structure to the settimeofday system call.  On
all other operating systems, and on Linux architectures that don’t
define __NR_settimeofday, __settimezone is a stub that always sets
errno to ENOSYS and returns -1.

Another complication is that the alpha-linux-gnu configuration has two
versions of settimeofday, GLIBC_2.0 and GLIBC_2.1, with the older
symbol using 32-bit time_t (yes, really).  The older symbol is
reimplemented from scratch (with the same semantics); the newer symbol
uses the generic implementation with some #ifdeffage to get the
versioning right.  Henceforth, __NR_osf_settimeofday will never be
used, and __NR_settimeofday only for the timezone feature.

There are no longer any internal callers of __settimeofday, so the
internal prototype is removed.

	* time/settimeofday.c (settimeofday): No longer a stub
	implementation.  Call __clock_settime or __settimezone depending
	on arguments.  Optionally override the default symbol version for
	settimeofday.
	* include/sys/time.h: Remove prototype for __settimeofday.
	Add prototype for __settimezone.
	* sysdeps/unix/syscalls.list: Remove entry for settimeofday.

	* time/settimezone.c: New file.
	(__settimezone): New stub implementation.
	* sysdeps/unix/sysv/linux/settimezone.c: New file.
	(__settimezone): Implement using settimeofday system call,
	if available.
	* time/Makefile (routines): Add settimezone.

	* sysdeps/unix/sysv/linux/alpha/syscalls.list:
	Remove entries for settimeofday and osf_settimeofday.
	* sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c
	New file, defines settimeofday@GLIBC_2.0.
	* sysdeps/unix/sysv/linux/alpha/settimeofday.c:
	New file, defines settimeofday@@GLIBC_2.1.
---
 include/sys/time.h                            |  3 +-
 sysdeps/unix/syscalls.list                    |  1 -
 .../unix/sysv/linux/alpha/osf_settimeofday.c  | 55 +++++++++++++++++++
 sysdeps/unix/sysv/linux/alpha/settimeofday.c  | 22 ++++++++
 sysdeps/unix/sysv/linux/alpha/syscalls.list   |  2 -
 sysdeps/unix/sysv/linux/settimezone.c         | 39 +++++++++++++
 time/Makefile                                 |  2 +-
 time/settimeofday.c                           | 24 ++++++--
 time/settimezone.c                            | 28 ++++++++++
 9 files changed, 166 insertions(+), 10 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c
 create mode 100644 sysdeps/unix/sysv/linux/alpha/settimeofday.c
 create mode 100644 sysdeps/unix/sysv/linux/settimezone.c
 create mode 100644 time/settimezone.c

Patch

diff --git a/include/sys/time.h b/include/sys/time.h
index 7ba0ca7c2d..a57752e8c7 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -24,8 +24,7 @@  extern int __gettimeofday (struct timeval *__tv,
 			   struct timezone *__tz);
 libc_hidden_proto (__gettimeofday)
 libc_hidden_proto (gettimeofday)
-extern int __settimeofday (const struct timeval *__tv,
-			   const struct timezone *__tz)
+extern int __settimezone (const struct timezone *__tz)
 	attribute_hidden;
 extern int __adjtime (const struct timeval *__delta,
 		      struct timeval *__olddelta);
diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
index 61e5360b4d..5fedd5733d 100644
--- a/sysdeps/unix/syscalls.list
+++ b/sysdeps/unix/syscalls.list
@@ -76,7 +76,6 @@  setreuid	-	setreuid	i:ii	__setreuid	setreuid
 setrlimit	-	setrlimit	i:ip	__setrlimit setrlimit
 setsid		-	setsid		i:	__setsid	setsid
 setsockopt	-	setsockopt	i:iiibn	setsockopt	__setsockopt
-settimeofday	-	settimeofday	i:PP	__settimeofday	settimeofday
 setuid		-	setuid		i:i	__setuid	setuid
 shutdown	-	shutdown	i:ii	shutdown
 sigaction	-	sigaction	i:ipp	__sigaction	sigaction
diff --git a/sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c b/sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c
new file mode 100644
index 0000000000..a61fcab482
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c
@@ -0,0 +1,55 @@ 
+/* settimeofday -- Set the current time of day.  Linux/Alpha/tv32 version.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+
+struct timeval32
+{
+    int tv_sec, tv_usec;
+};
+
+/* Set the current time of day and timezone information.
+   This call is restricted to the super-user.  */
+int
+attribute_compat_text_section
+__settimeofday_tv32 (const struct timeval32 *tv32,
+                     const struct timezone *tz)
+{
+  if (__glibc_unlikely (tz != 0))
+    {
+      if (tv32 != 0)
+	{
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+      return __settimezone (tz);
+    }
+
+  struct timespec ts;
+  ts.tv_sec = tv32->tv_sec;
+  ts.tv_nsec = tv32->tv_usec * 1000;
+  return __clock_settime (CLOCK_REALTIME, &ts);
+}
+
+compat_symbol (libc, __settimeofday_tv32, settimeofday, GLIBC_2_0);
+#endif
diff --git a/sysdeps/unix/sysv/linux/alpha/settimeofday.c b/sysdeps/unix/sysv/linux/alpha/settimeofday.c
new file mode 100644
index 0000000000..36a6901e4e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/settimeofday.c
@@ -0,0 +1,22 @@ 
+/* settimeofday -- Set the current time of day.  Linux/Alpha/tv64 version.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* We can use the generic implementation, but we have to override its
+   default symbol version.  */
+#define VERSION_settimeofday GLIBC_2.1
+#include <time/settimeofday.c>
diff --git a/sysdeps/unix/sysv/linux/alpha/syscalls.list b/sysdeps/unix/sysv/linux/alpha/syscalls.list
index 12cd021b60..f5a534ed68 100644
--- a/sysdeps/unix/sysv/linux/alpha/syscalls.list
+++ b/sysdeps/unix/sysv/linux/alpha/syscalls.list
@@ -24,7 +24,6 @@  pciconfig_iobase EXTRA	pciconfig_iobase 3	__pciconfig_iobase pciconfig_iobase
 
 # support old timeval32 entry points
 osf_gettimeofday -	osf_gettimeofday 2	__gettimeofday_tv32  __gettimeofday@GLIBC_2.0 gettimeofday@GLIBC_2.0
-osf_settimeofday -	osf_settimeofday 2	__settimeofday_tv32  settimeofday@GLIBC_2.0
 osf_getitimer	-	osf_getitimer	2	__getitimer_tv32  getitimer@GLIBC_2.0
 osf_setitimer	-	osf_setitimer	3	__setitimer_tv32  setitimer@GLIBC_2.0
 osf_utimes	-	osf_utimes	2	__utimes_tv32  utimes@GLIBC_2.0
@@ -33,7 +32,6 @@  osf_wait4	-	osf_wait4	4	__wait4_tv32  wait4@GLIBC_2.0
 
 # support new timeval64 entry points
 gettimeofday	-	gettimeofday	2	__GI___gettimeofday gettimeofday@@GLIBC_2.1 __gettimeofday@@GLIBC_2.1
-settimeofday	-	settimeofday	2	__settimeofday settimeofday@@GLIBC_2.1
 getitimer	-	getitimer	2	__getitimer getitimer@@GLIBC_2.1
 setitimer	-	setitimer	3	__setitimer setitimer@@GLIBC_2.1
 utimes		-	utimes		2	__utimes utimes@@GLIBC_2.1
diff --git a/sysdeps/unix/sysv/linux/settimezone.c b/sysdeps/unix/sysv/linux/settimezone.c
new file mode 100644
index 0000000000..823f4fe42f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/settimezone.c
@@ -0,0 +1,39 @@ 
+/* Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/time.h>
+#include <sysdep.h>
+
+/* Set the system-wide timezone.
+   This call is restricted to the super-user.
+   This operation is considered obsolete, kernel support may not be
+   available on all architectures.  */
+
+#ifdef __NR_settimeofday
+
+int
+__settimezone (const struct timezone *tz)
+{
+  return INLINE_SYSCALL_CALL (settimeofday, NULL, tz);
+}
+
+#else
+
+#include <time/settimezone.c>
+
+#endif
diff --git a/time/Makefile b/time/Makefile
index a428f55245..d78bff85e6 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -36,7 +36,7 @@  routines := offtime asctime clock ctime ctime_r difftime \
 	    stime dysize timegm ftime			 \
 	    getdate strptime strptime_l			 \
 	    strftime wcsftime strftime_l wcsftime_l	 \
-	    timespec_get
+	    timespec_get settimezone
 aux :=	    era alt_digit lc-time-cleanup
 
 tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
diff --git a/time/settimeofday.c b/time/settimeofday.c
index 4620559652..78f666e352 100644
--- a/time/settimeofday.c
+++ b/time/settimeofday.c
@@ -16,6 +16,7 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
+#include <time.h>
 #include <sys/time.h>
 
 /* Set the current time of day and timezone information.
@@ -23,9 +24,24 @@ 
 int
 __settimeofday (const struct timeval *tv, const struct timezone *tz)
 {
-  __set_errno (ENOSYS);
-  return -1;
+  if (__glibc_unlikely (tz != 0))
+    {
+      if (tv != 0)
+	{
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+      return __settimezone (tz);
+    }
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (tv, &ts);
+  return __clock_settime (CLOCK_REALTIME, &ts);
 }
-stub_warning (settimeofday)
 
-weak_alias (__settimeofday, settimeofday)
+#ifdef VERSION_settimeofday
+weak_alias (__settimeofday, __settimeofday_w);
+default_symbol_version (__settimeofday_w, settimeofday, VERSION_settimeofday);
+#else
+weak_alias (__settimeofday, settimeofday);
+#endif
diff --git a/time/settimezone.c b/time/settimezone.c
new file mode 100644
index 0000000000..eb005da213
--- /dev/null
+++ b/time/settimezone.c
@@ -0,0 +1,28 @@ 
+/* Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/time.h>
+
+/* Set the system-wide timezone.
+   This call is restricted to the super-user.  */
+int
+__settimezone (const struct timezone *tz)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}