summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/TODO2
-rw-r--r--sys-utils/hwclock-cmos.c6
-rw-r--r--sys-utils/hwclock-rtc.c6
-rw-r--r--sys-utils/hwclock.8.in18
-rw-r--r--sys-utils/hwclock.c76
-rw-r--r--sys-utils/hwclock.h2
6 files changed, 102 insertions, 8 deletions
diff --git a/Documentation/TODO b/Documentation/TODO
index 488cc0677..44c980581 100644
--- a/Documentation/TODO
+++ b/Documentation/TODO
@@ -65,8 +65,6 @@ hwlock
- use /etc/adjtime as read-only for UTC/LOCAL information only
- the /var/lib/hwclock/drift should be implemented backwardly compatible,
it means use the file only if exists, otherwise follow /etc/adjtime
- - add --delay-on-set <ms> to make possible to by-pass default 500ms delay on --set
- https://marc.info/?l=util-linux-ng&m=146675599623002&w=2
bash completion
---------------
diff --git a/sys-utils/hwclock-cmos.c b/sys-utils/hwclock-cmos.c
index f7e8a1811..426ef4c23 100644
--- a/sys-utils/hwclock-cmos.c
+++ b/sys-utils/hwclock-cmos.c
@@ -393,12 +393,18 @@ static int get_permissions_cmos(void)
return rc;
}
+static get_device_path(void)
+{
+ return NULL;
+}
+
static struct clock_ops cmos_interface = {
N_("Using direct ISA access to the clock"),
get_permissions_cmos,
read_hardware_clock_cmos,
set_hardware_clock_cmos,
synchronize_to_clock_tick_cmos,
+ get_device_path,
};
/*
diff --git a/sys-utils/hwclock-rtc.c b/sys-utils/hwclock-rtc.c
index ef95d9807..3b069d7aa 100644
--- a/sys-utils/hwclock-rtc.c
+++ b/sys-utils/hwclock-rtc.c
@@ -369,12 +369,18 @@ static int get_permissions_rtc(void)
return 0;
}
+static const char *get_device_path(void)
+{
+ return rtc_dev_name;
+}
+
static 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 */
diff --git a/sys-utils/hwclock.8.in b/sys-utils/hwclock.8.in
index b9f618973..729b1ddae 100644
--- a/sys-utils/hwclock.8.in
+++ b/sys-utils/hwclock.8.in
@@ -280,6 +280,24 @@ parameters should be observed.
.RE
.
.TP
+.BI \%\-\-delay= seconds
+This option allows to overwrite internally used delay when set clock time. The
+default is 0.5 (500ms) for rtc_cmos, for another RTC types the delay is 0. If
+RTC type is impossible to determine (from sysfs) then it defaults also to 0.5
+to be backwardly compatible.
+.RS
+.PP
+The 500ms default is based on commonly used MC146818A-compatible (x86) hardware clock. This
+Hardware Clock can only be set to any integer time plus one half second. The
+integer time is required because there is no interface to set or get a
+fractional second. The additional half second delay is because the Hardware
+Clock updates to the following second precisely 500 ms after setting the new
+time. Unfortunately, this behavior is hardware specific and in same cases
+another delay is required.
+.RE
+.
+.TP
+.TP
.BR \-D ", " \-\-debug
.RB Use\ \-\-verbose .
.RB The\ \%\-\-debug\ option
diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
index b83e71004..d9acbaf7d 100644
--- a/sys-utils/hwclock.c
+++ b/sys-utils/hwclock.c
@@ -78,6 +78,8 @@
#include "timeutils.h"
#include "env.h"
#include "xalloc.h"
+#include "path.h"
+#include "strutils.h"
#ifdef HAVE_LIBAUDIT
#include <libaudit.h>
@@ -409,6 +411,47 @@ set_hardware_clock(const struct hwclock_control *ctl, const time_t newtime)
ur->set_hardware_clock(ctl, &new_broken_time);
}
+static double
+get_hardware_delay(const struct hwclock_control *ctl)
+{
+ const char *devpath, *rtcname;
+ char name[128 + 1];
+ struct path_cxt *pc;
+ int rc;
+
+ devpath = ur->get_device_path();
+ if (!devpath)
+ goto unknown;
+
+ rtcname = strrchr(devpath, '/');
+ if (!rtcname || !*(rtcname + 1))
+ goto unknown;
+ rtcname++;
+
+ pc = ul_new_path("/sys/class/rtc/%s", rtcname);
+ if (!pc)
+ goto unknown;
+ rc = ul_path_scanf(pc, "name", "%128[^\n ]", &name);
+ ul_unref_path(pc);
+
+ if (rc != 1 || !*name)
+ goto unknown;
+
+ if (ctl->verbose)
+ printf(_("RTC type: '%s'\n"), name);
+
+ /* MC146818A-compatible (x86) */
+ if (strcmp(name, "rtc_cmos") == 0)
+ return 0.5;
+
+ /* Another HW */
+ return 0;
+unknown:
+ /* Let's be backwardly compatible */
+ return 0.5;
+}
+
+
/*
* Set the Hardware Clock to the time "sethwtime", in local time zone or
* UTC, according to "universal".
@@ -418,7 +461,8 @@ set_hardware_clock(const struct hwclock_control *ctl, const time_t newtime)
* example, if "sethwtime" is 14:03:05 and "refsystime" is 12:10:04.5 and
* the current system time is 12:10:06.0: Wait .5 seconds (to make exactly 2
* seconds since "refsystime") and then set the Hardware Clock to 14:03:07,
- * thus getting a precise and retroactive setting of the clock.
+ * thus getting a precise and retroactive setting of the clock. The .5 delay is
+ * default on x86, see --delay and get_hardware_delay().
*
* (Don't be confused by the fact that the system clock and the Hardware
* Clock differ by two hours in the above example. That's just to remind you
@@ -480,15 +524,26 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
time_t newhwtime = sethwtime;
double target_time_tolerance_secs = 0.001; /* initial value */
double tolerance_incr_secs = 0.001; /* initial value */
- const double RTC_SET_DELAY_SECS = 0.5; /* 500 ms */
- const struct timeval RTC_SET_DELAY_TV = { 0, RTC_SET_DELAY_SECS * 1E6 };
+ double delay;
+ struct timeval rtc_set_delay_tv;
struct timeval targetsystime;
struct timeval nowsystime;
struct timeval prevsystime = refsystime;
double deltavstarget;
- timeradd(&refsystime, &RTC_SET_DELAY_TV, &targetsystime);
+ if (ctl->rtc_delay != -1.0) /* --delay specified */
+ delay = ctl->rtc_delay;
+ else
+ delay = get_hardware_delay(ctl);
+
+ if (ctl->verbose)
+ printf(_("Using delay: %.6f seconds\n"), delay);
+
+ rtc_set_delay_tv.tv_sec = 0;
+ rtc_set_delay_tv.tv_usec = delay * 1E6;
+
+ timeradd(&refsystime, &rtc_set_delay_tv, &targetsystime);
while (1) {
double ticksize;
@@ -549,7 +604,7 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
newhwtime = sethwtime
+ (int)(time_diff(nowsystime, refsystime)
- - RTC_SET_DELAY_SECS /* don't count this */
+ - delay /* don't count this */
+ 0.5 /* for rounding */);
if (ctl->verbose)
printf(_("%ld.%06ld is close enough to %ld.%06ld (%.6f < %.6f)\n"
@@ -1082,6 +1137,7 @@ usage(void)
printf(_(
" --directisa use the ISA bus instead of %1$s access\n"), _PATH_RTC_DEV);
puts(_(" --date <time> date/time input for --set and --predict"));
+ puts(_(" --delay <sec> delay used when set new RTC time"));
#if defined(__linux__) && defined(__alpha__)
puts(_(" --epoch <year> epoch input for --setepoch"));
#endif
@@ -1100,7 +1156,10 @@ usage(void)
int main(int argc, char **argv)
{
- struct hwclock_control ctl = { .show = 1 }; /* default op is show */
+ struct hwclock_control ctl = {
+ .show = 1, /* default op is show */
+ .rtc_delay = -1.0 /* unspecified */
+ };
struct timeval startup_time;
struct adjtime adjtime = { 0 };
struct timespec when = { 0 };
@@ -1115,6 +1174,7 @@ int main(int argc, char **argv)
enum {
OPT_ADJFILE = CHAR_MAX + 1,
OPT_DATE,
+ OPT_DELAY,
OPT_DIRECTISA,
OPT_EPOCH,
OPT_GET,
@@ -1150,6 +1210,7 @@ int main(int argc, char **argv)
{ "directisa", no_argument, NULL, OPT_DIRECTISA },
{ "test", no_argument, NULL, OPT_TEST },
{ "date", required_argument, NULL, OPT_DATE },
+ { "delay", required_argument, NULL, OPT_DELAY },
#ifdef __linux__
{ "rtc", required_argument, NULL, 'f' },
#endif
@@ -1271,6 +1332,9 @@ int main(int argc, char **argv)
case OPT_DATE:
ctl.date_opt = optarg; /* --date */
break;
+ case OPT_DELAY:
+ ctl.rtc_delay = strtod_or_err(optarg, "invalid --delay argument");
+ break;
case OPT_ADJFILE:
ctl.adj_file_name = optarg; /* --adjfile */
break;
diff --git a/sys-utils/hwclock.h b/sys-utils/hwclock.h
index 7bb6ec8bd..92fdb5f82 100644
--- a/sys-utils/hwclock.h
+++ b/sys-utils/hwclock.h
@@ -22,6 +22,7 @@ UL_DEBUG_DECLARE_MASK(hwclock);
struct hwclock_control {
char *date_opt;
char *adj_file_name;
+ double rtc_delay; /* --delay <seconds> */
#if defined(__linux__) && defined(__alpha__)
char *epoch_option;
#endif
@@ -58,6 +59,7 @@ struct clock_ops {
int (*read_hardware_clock) (const struct hwclock_control *ctl, struct tm * tm);
int (*set_hardware_clock) (const struct hwclock_control *ctl, const struct tm * tm);
int (*synchronize_to_clock_tick) (const struct hwclock_control *ctl);
+ const char *(*get_device_path) (void);
};
extern struct clock_ops *probe_for_cmos_clock(void);