This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH v2 04/11] Use clock_settime to implement settimeofday.
On Fri, Oct 25, 2019 at 5:09 AM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> From: Zack Weinberg <zackw@panix.com>
>
> Use clock_settime to implement settimeofday.
>
> Changes from previous version:
>
> - Added a NEWS entry.
>
> --
>
> Unconditionally, on all ports, use clock_settime to implement
> settimeofday. Remove sysdeps/unix/clock_settime.c, which implemented
> clock_settime by calling settimeofday; new OS ports must henceforth
> provide a real implementation of clock_settime.
>
> Hurd had a real implementation of settimeofday but not of
> clock_settime; this patch converts it into an implementation of
> clock_settime. It only supports CLOCK_REALTIME and microsecond
> resolution; Hurd/Mach does not appear to have any support for
> finer-resolution clocks.
>
> The vestigial "set time zone" feature of settimeofday complicates the
> generic settimeofday implementation a little. 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). There currently isn't any other way to
> do this. However, the callers that do this 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.
>
> The settimeoday syscall is enabled on Linux by the flag
> COMPAT_32BIT_TIME, which is an option to either 32-bits ABIs or COMPAT
> builds (defined usually by 64-bit kernels that want to support 32-bit
> ABIs, such as x86). The idea to future 64-bit time_t only ABIs
> is to not provide settimeofday syscall.
>
> The same semantics are implemented for Linux/Alpha's GLIBC_2.0 compat
> symbol for settimeofday.
>
> There are no longer any internal callers of __settimeofday, so the
> internal prototype is removed.
>
> Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc64le-linux-gnu,
> powerpc64-linux-gnu, powerpc-linux-gnu, and aarch64-linux-gnu.
>
> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> NEWS | 24 +++++++++
> include/sys/time.h | 3 +-
> sysdeps/{unix => mach/hurd}/clock_settime.c | 51 ++++++++-----------
> sysdeps/unix/syscalls.list | 1 -
> .../unix/sysv/linux/alpha/osf_settimeofday.c | 16 ++++--
> sysdeps/unix/sysv/linux/alpha/settimeofday.c | 22 ++++++++
> sysdeps/unix/sysv/linux/alpha/syscalls.list | 1 -
> sysdeps/unix/sysv/linux/settimezone.c | 36 +++++++++++++
> time/Makefile | 8 +--
> time/settimeofday.c | 24 +++++++--
> .../hurd/settimeofday.c => time/settimezone.c | 34 ++-----------
> 11 files changed, 147 insertions(+), 73 deletions(-)
> rename sysdeps/{unix => mach/hurd}/clock_settime.c (65%)
> create mode 100644 sysdeps/unix/sysv/linux/alpha/settimeofday.c
> create mode 100644 sysdeps/unix/sysv/linux/settimezone.c
> rename sysdeps/mach/hurd/settimeofday.c => time/settimezone.c (52%)
>
> diff --git a/NEWS b/NEWS
> index 8727b5e7f0..0b1476e745 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -34,6 +34,30 @@ Deprecated and removed features, and other changes affecting compatibility:
> binaries and it has been removed from <time.h> header. This function
> has been deprecated in favor of clock_settime.
>
> +* The settimeofday function can still be used to set a system-wide time
> + zone when the operating system supports it. This is because the Linux
> + kernel reused the API, on some architectures, to describe a system-wide
> + time-zone-like offset between the software clock maintained by the kernel,
> + and the “RTC” clock that keeps time when the system is shut down.
> +
> + However, to reduce the odds of this offset being set by accident,
> + 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).
> +
> + Callers attempting to set this offset should also be prepared for the call
> + to fail and set errno to ENOSYS; this already happens on the Hurd and on
> + some Linux architectures. The Linux kernel maintainers are discussing a
> + more principled replacement for the reused API. After a replacement
> + becomes available, we will change settimeofday to fail with ENOSYS on all
> + platforms when its ‘tzp’ argument is not a null pointer.
> +
> + Note that settimeofday itself is obsolescent according to POSIX.
> + Programs that set the system time should use clock_settime and/or
> + the adjtime family of functions instead. We may also cease to make
> + settimeofday available to newly linked binaries after there is a
> + replacement for Linux’s time-zone-like offset API.
> +
> Changes to build and runtime requirements:
>
> [Add changes to build and runtime requirements here]
> diff --git a/include/sys/time.h b/include/sys/time.h
> index 57208afa82..c0e30e70fb 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/clock_settime.c b/sysdeps/mach/hurd/clock_settime.c
> similarity index 65%
> rename from sysdeps/unix/clock_settime.c
> rename to sysdeps/mach/hurd/clock_settime.c
> index 18d7c99864..02239c097a 100644
> --- a/sysdeps/unix/clock_settime.c
> +++ b/sysdeps/mach/hurd/clock_settime.c
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1999-2019 Free Software Foundation, Inc.
> +/* Copyright (C) 1991-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
> @@ -17,38 +17,31 @@
>
> #include <errno.h>
> #include <time.h>
> -#include <sys/time.h>
> +#include <hurd.h>
> +#include <hurd/port.h>
> #include <shlib-compat.h>
>
> -/* Set CLOCK to value TP. */
> +/* Set the current time of day.
> + This call is restricted to the super-user. */
> int
> -__clock_settime (clockid_t clock_id, const struct timespec *tp)
> +__clock_settime (clockid_t clock_id, const struct timespec *ts)
> {
> - int retval = -1;
> -
> - /* Make sure the time cvalue is OK. */
> - if (tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000)
> - {
> - __set_errno (EINVAL);
> - return -1;
> - }
> -
> - switch (clock_id)
> - {
> - case CLOCK_REALTIME:
> - {
> - struct timeval tv;
> - TIMESPEC_TO_TIMEVAL (&tv, tp);
> - retval = __settimeofday (&tv, NULL);
> - }
> - break;
> -
> - default:
> - __set_errno (EINVAL);
> - break;
> - }
> -
> - return retval;
> + error_t err;
> + mach_port_t hostpriv;
> + time_value_t tv;
> +
> + if (clock_id != CLOCK_REALTIME)
> + return __hurd_fail (EINVAL);
> +
> + err = __get_privileged_ports (&hostpriv, NULL);
> + if (err)
> + return __hurd_fail (EPERM);
> +
> + TIMESPEC_TO_TIME_VALUE (&tv, ts);
> + err = __host_set_time (hostpriv, tv);
> + __mach_port_deallocate (__mach_task_self (), hostpriv);
> +
> + return __hurd_fail (err);
> }
> libc_hidden_def (__clock_settime)
>
> 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
> index fb2a36df19..914f5ac57b 100644
> --- a/sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c
> +++ b/sysdeps/unix/sysv/linux/alpha/osf_settimeofday.c
> @@ -32,9 +32,19 @@ attribute_compat_text_section
> __settimeofday_tv32 (const struct timeval32 *tv32,
> const struct timezone *tz)
> {
> - struct timeval tv;
> - tv32_to_tv64 (&tv, tv32);
> - return __settimeofday (&tv, tz);
> + if (__glibc_unlikely (tz != 0))
> + {
> + if (tv32 != 0)
> + {
> + __set_errno (EINVAL);
> + return -1;
> + }
> + return __settimezone (tz);
> + }
> +
> + struct timespec ts;
> + tv32_to_ts64 (&ts, tv32);
> + return __clock_settime (CLOCK_REALTIME, &ts);
> }
>
> compat_symbol (libc, __settimeofday_tv32, settimeofday, GLIBC_2_0);
> 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 c786aa751e..95a27e18e8 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
>
> # timeval64 entry points (see osf_*.c for GLIBC_2.0 timeval32 equivalents)
> gettimeofday - gettimeofday i:pP __GI___gettimeofday gettimeofday@@GLIBC_2.1 __gettimeofday@@GLIBC_2.1
> -settimeofday - settimeofday i:PP __settimeofday settimeofday@@GLIBC_2.1
> getitimer - getitimer i:ip __getitimer getitimer@@GLIBC_2.1
> setitimer - setitimer i:ipP __setitimer setitimer@@GLIBC_2.1
> utimes - utimes i:sp __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..90b38307c6
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/settimezone.c
> @@ -0,0 +1,36 @@
> +/* Obsolete set system time. Linux 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 <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. */
> +int
> +__settimezone (const struct timezone *tz)
> +{
> +#ifdef __NR_settimeofday
> + return INLINE_SYSCALL_CALL (settimeofday, NULL, tz);
> +#else
> + __set_errno (ENOSYS);
> + return -1
You are missing a semi-colon here.
Alistair
> +#endif
> +}
> diff --git a/time/Makefile b/time/Makefile
> index ad8844ea34..6de4e418d9 100644
> --- a/time/Makefile
> +++ b/time/Makefile
> @@ -31,13 +31,13 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
>
> routines := offtime asctime clock ctime ctime_r difftime \
> gmtime localtime mktime time \
> - gettimeofday settimeofday adjtime tzset \
> - tzfile getitimer setitimer \
> + gettimeofday settimeofday settimezone \
> + adjtime tzset tzfile getitimer setitimer \
> stime dysize timegm ftime \
> getdate strptime strptime_l \
> strftime wcsftime strftime_l wcsftime_l \
> - timespec_get \
> - clock_getcpuclockid clock_getres \
> + timespec_get \
> + clock_getcpuclockid clock_getres \
> clock_gettime clock_settime clock_nanosleep
>
> aux := era alt_digit lc-time-cleanup
> diff --git a/time/settimeofday.c b/time/settimeofday.c
> index 6aa4832d65..ad57ad41a1 100644
> --- a/time/settimeofday.c
> +++ b/time/settimeofday.c
> @@ -16,6 +16,7 @@
> <https://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/sysdeps/mach/hurd/settimeofday.c b/time/settimezone.c
> similarity index 52%
> rename from sysdeps/mach/hurd/settimeofday.c
> rename to time/settimezone.c
> index 31bffcad9d..b9969c9dd5 100644
> --- a/sysdeps/mach/hurd/settimeofday.c
> +++ b/time/settimezone.c
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1991-2019 Free Software Foundation, Inc.
> +/* 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
> @@ -17,36 +17,12 @@
>
> #include <errno.h>
> #include <sys/time.h>
> -#include <hurd.h>
> -#include <hurd/port.h>
>
> -/* Set the current time of day and timezone information.
> +/* Set the system-wide timezone.
> This call is restricted to the super-user. */
> int
> -__settimeofday (const struct timeval *tv, const struct timezone *tz)
> +__settimezone (const struct timezone *tz)
> {
> - error_t err;
> - mach_port_t hostpriv;
> -
> - if (tz != NULL)
> - {
> - errno = ENOSYS;
> - return -1;
> - }
> -
> - err = __get_privileged_ports (&hostpriv, NULL);
> - if (err)
> - return __hurd_fail (EPERM);
> -
> - /* `time_value_t' and `struct timeval' are in fact identical with the
> - names changed. */
> - err = __host_set_time (hostpriv, *(time_value_t *) tv);
> - __mach_port_deallocate (__mach_task_self (), hostpriv);
> -
> - if (err)
> - return __hurd_fail (err);
> -
> - return 0;
> + __set_errno (ENOSYS);
> + return -1;
> }
> -
> -weak_alias (__settimeofday, settimeofday)
> --
> 2.17.1
>