bug-hurd
[Top][All Lists]
Advanced

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

[RFC PATCH util-linux] Support hwclock read and set operations for Hurd


From: Zhaoming Luo
Subject: [RFC PATCH util-linux] Support hwclock read and set operations for Hurd
Date: Mon, 2 Dec 2024 10:06:48 +0800

From: Zhaoming Luo <zhaoming1357@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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]