From: Zhaoming Luo <zhaoming1...@qq.com> * configure.ac: add HURD conditional for meson build * sys-utils/Makemodule.am: compile hurd-specific rtc device operations * sys-utils/hurd-hwclock-rtc.c: new file, hurd-specific rtc device * operations * sys-utils/hwclock.c: add --rtc option and probe_for_rtc_clock for hwclock in Hurd * sys-utils/hwclock.h: add variable for storing rtc device name in Hurd
--- configure.ac | 6 +- sys-utils/Makemodule.am | 4 + sys-utils/hurd-hwclock-rtc.c | 193 +++++++++++++++++++++++++++++++++++ sys-utils/hwclock.c | 8 +- sys-utils/hwclock.h | 3 + 5 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 sys-utils/hurd-hwclock-rtc.c diff --git a/configure.ac b/configure.ac index 698da36..8de6af6 100644 --- a/configure.ac +++ b/configure.ac @@ -263,16 +263,20 @@ AC_PATH_PROG([XSLTPROC], [xsltproc]) linux_os=no bsd_os=no +gnu_os=no AS_CASE([${host_os}], [*linux*], [linux_os=yes], [*darwin*], [darwin_os=yes], [*bsd*], - [bsd_os=yes]) + [bsd_os=yes], + [gnu*], + [gnu_os=yes]) AM_CONDITIONAL([LINUX], [test "x$linux_os" = xyes]) AM_CONDITIONAL([DARWIN], [test "x$darwin_os" = xyes]) AM_CONDITIONAL([BSD], [test "x$bsd_os" = xyes]) +AM_CONDITIONAL([HURD], [test "x$gnu_os" = xyes]) AS_IF([test "x$darwin_os" = xyes], [ AC_DEFINE([_DARWIN_C_SOURCE], [1], [Enable MAP_ANON in sys/mman.h on Mac OS X]) diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am index 209b656..7582106 100644 --- a/sys-utils/Makemodule.am +++ b/sys-utils/Makemodule.am @@ -570,6 +570,10 @@ hwclock_SOURCES += \ lib/monotonic.c hwclock_LDADD += $(REALTIME_LIBS) endif +if HURD +hwclock_SOURCES += \ + sys-utils/hurd-hwclock-rtc.c +endif if HAVE_AUDIT hwclock_LDADD += -laudit endif diff --git a/sys-utils/hurd-hwclock-rtc.c b/sys-utils/hurd-hwclock-rtc.c new file mode 100644 index 0000000..4c388fe --- /dev/null +++ b/sys-utils/hurd-hwclock-rtc.c @@ -0,0 +1,193 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * hurd-hwclock-rtc.c - Use /dev/rtc for clock access in GNU Hurd + */ +#include <sys/ioctl.h> +#include <hurd/rtc.h> + +#include "hwclock.h" + +/* default or user defined dev (by hwclock --rtc=<path>) */ +static const char *rtc_dev_name; +static int rtc_dev_fd = -1; + +static void close_rtc(void) +{ + if (rtc_dev_fd != -1) + close(rtc_dev_fd); + rtc_dev_fd = -1; +} + +static int open_rtc(const struct hwclock_control *ctl) +{ + static const char * const fls[] = { +#ifdef __ia64__ + "/dev/efirtc", + "/dev/misc/efirtc", +#endif + "/dev/rtc0", + "/dev/rtc", + "/dev/misc/rtc" + }; + size_t i; + + if (rtc_dev_fd != -1) + return rtc_dev_fd; + + /* --rtc option has been given */ + if (ctl->rtc_dev_name) { + rtc_dev_name = ctl->rtc_dev_name; + rtc_dev_fd = open(rtc_dev_name, O_RDONLY | O_WRONLY); + } else { + for (i = 0; i < ARRAY_SIZE(fls); i++) { + if (ctl->verbose) + printf(_("Trying to open: %s\n"), fls[i]); + rtc_dev_fd = open(fls[i], O_RDONLY | O_WRONLY); + + if (rtc_dev_fd < 0) { + if (errno == ENOENT || errno == ENODEV) + continue; + if (ctl->verbose) + warn(_("cannot open %s"), fls[i]); + } + rtc_dev_name = fls[i]; + break; + } + if (rtc_dev_fd < 0) + rtc_dev_name = *fls; /* default for error messages */ + } + if (rtc_dev_fd != -1) + atexit(close_rtc); + return rtc_dev_fd; +} + +/* + * Not yet implemented + */ +static int synchronize_to_clock_tick_rtc([[maybe_unused]] const struct hwclock_control *ctl) +{ + return 0; +} + +static int open_rtc_or_exit(const struct hwclock_control *ctl) +{ + int rtc_fd = open_rtc(ctl); + + if (rtc_fd < 0) { + warn(_("cannot open rtc device")); + hwclock_exit(ctl, EXIT_FAILURE); + } + return rtc_fd; +} + +static int do_rtc_read_ioctl(int rtc_fd, struct tm *tm) +{ + int rc = -1; + struct rtc_time rtc_tm = { 0 }; + + rc = ioctl(rtc_fd, RTC_RD_TIME, &rtc_tm); + + if (rc == -1) { + warn(_("ioctl(RTC_RD_NAME) to %s to read the time failed"), + rtc_dev_name); + return -1; + } + + /* kernel uses private struct tm definition to be self contained */ + tm->tm_sec = rtc_tm.tm_sec; + tm->tm_min = rtc_tm.tm_min; + tm->tm_hour = rtc_tm.tm_hour; + tm->tm_mday = rtc_tm.tm_mday; + tm->tm_mon = rtc_tm.tm_mon; + tm->tm_year = rtc_tm.tm_year; + tm->tm_wday = rtc_tm.tm_wday; + tm->tm_yday = rtc_tm.tm_yday; + tm->tm_isdst = -1; /* don't know whether it's dst */ + return 0; +} + +static int read_hardware_clock_rtc(const struct hwclock_control *ctl, + struct tm *tm) +{ + int rtc_fd, rc; + + rtc_fd = open_rtc_or_exit(ctl); + + /* Read the RTC time/date, return answer via tm */ + rc = do_rtc_read_ioctl(rtc_fd, tm); + + return rc; +} + +/* + * Set the Hardware Clock to the broken down time <new_broken_time>. Use + * ioctls to "rtc" device /dev/rtc. + */ +static int set_hardware_clock_rtc(const struct hwclock_control *ctl, + const struct tm *new_broken_time) +{ + int rc = -1; + int rtc_fd; + struct rtc_time rtc_tm = { 0 }; + + rtc_fd = open_rtc_or_exit(ctl); + + /* kernel uses private struct tm definition to be self contained */ + rtc_tm.tm_sec = new_broken_time->tm_sec; + rtc_tm.tm_min = new_broken_time->tm_min; + rtc_tm.tm_hour = new_broken_time->tm_hour; + rtc_tm.tm_mday = new_broken_time->tm_mday; + rtc_tm.tm_mon = new_broken_time->tm_mon; + rtc_tm.tm_year = new_broken_time->tm_year; + rtc_tm.tm_wday = new_broken_time->tm_wday; + rtc_tm.tm_yday = new_broken_time->tm_yday; + rtc_tm.tm_isdst = new_broken_time->tm_isdst; + + rc = ioctl(rtc_fd, RTC_SET_TIME, &rtc_tm); + + if (rc == -1) { + warn(_("ioctl(RTC_SET_TIME) to %s to set the time failed"), + rtc_dev_name); + hwclock_exit(ctl, EXIT_FAILURE); + } + + if (ctl->verbose) + printf(_("ioctl(RTC_SET_TIME) was successful.\n")); + + return 0; +} + +static int get_permissions_rtc(void) +{ + return 0; +} + +static const char *get_device_path(void) +{ + return rtc_dev_name; +} + +static const struct clock_ops rtc_interface = { + N_("Using the rtc interface to the clock."), + get_permissions_rtc, + read_hardware_clock_rtc, + set_hardware_clock_rtc, + synchronize_to_clock_tick_rtc, + get_device_path, +}; + +/* return &rtc if /dev/rtc can be opened, NULL otherwise */ +const struct clock_ops *probe_for_rtc_clock(const struct hwclock_control *ctl) +{ + const int rtc_fd = open_rtc(ctl); + + if (rtc_fd < 0) + return NULL; + return &rtc_interface; +} diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c index 2b33dfb..f29539f 100644 --- a/sys-utils/hwclock.c +++ b/sys-utils/hwclock.c @@ -989,7 +989,7 @@ static void determine_clock_access_method(const struct hwclock_control *ctl) if (ctl->directisa) ur = probe_for_cmos_clock(); #endif -#ifdef __linux__ +#if defined(__linux__) || defined(__gnu_hurd__) if (!ur) ur = probe_for_rtc_clock(ctl); #endif @@ -1249,7 +1249,7 @@ usage(void) fputs(USAGE_OPTIONS, stdout); puts(_(" -u, --utc the RTC timescale is UTC")); puts(_(" -l, --localtime the RTC timescale is Local")); -#ifdef __linux__ +#if defined(__linux__) || defined(__gnu_hurd__) printf(_( " -f, --rtc <file> use an alternate file to %1$s\n"), _PATH_RTC_DEV); #endif @@ -1356,7 +1356,7 @@ int main(int argc, char **argv) { "test", no_argument, NULL, OPT_TEST }, { "date", required_argument, NULL, OPT_DATE }, { "delay", required_argument, NULL, OPT_DELAY }, -#ifdef __linux__ +#if defined(__linux__) || defined(__gnu_hurd__) { "rtc", required_argument, NULL, 'f' }, #endif { "adjfile", required_argument, NULL, OPT_ADJFILE }, @@ -1521,7 +1521,7 @@ int main(int argc, char **argv) case OPT_UPDATE: ctl.update = 1; /* --update-drift */ break; -#ifdef __linux__ +#if defined(__linux__) || defined(__gnu_hurd__) case 'f': ctl.rtc_dev_name = optarg; /* --rtc */ break; diff --git a/sys-utils/hwclock.h b/sys-utils/hwclock.h index 2522d6c..485e904 100644 --- a/sys-utils/hwclock.h +++ b/sys-utils/hwclock.h @@ -39,6 +39,9 @@ struct hwclock_control { #ifdef __linux__ char *rtc_dev_name; uint32_t param_idx; /* --param-index <n> */ +#endif +#ifdef __gnu_hurd__ + char *rtc_dev_name; #endif char *param_get_option; char *param_set_option; -- 2.45.2