Hello Noé, I just submitted a patch on 14-09-27 that adds this functionality without creating a new state file. On 10/07/2014 05:15 AM, Noé Rubinstein wrote: > From: Noé Rubinstein <noe.rubinstein@xxxxxxxxx> > > This option is useful for systems that have a working hardware clock, but do > not provide a way to write to it. Instead of setting the hardware clock, write > the difference between hardware and system clock to a file; when getting the > hardware clock, add the offset from this file to obtain the correct time. > > I have not checked how well this interacts with the adjtime mechanism, so > this is an RFC patch. > --- > sys-utils/hwclock.8.in | 6 ++++ > sys-utils/hwclock.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 92 insertions(+), 2 deletions(-) > > diff --git a/sys-utils/hwclock.8.in b/sys-utils/hwclock.8.in > index b11b45c..63fabda 100644 > --- a/sys-utils/hwclock.8.in > +++ b/sys-utils/hwclock.8.in > @@ -113,6 +113,12 @@ not reset. > .BR \-w , \ \-\-systohc > Set the Hardware Clock to the current System Time. > .TP > +.BR \-\-offset[=filename] > +This option is useful for systems that have a working hardware clock, but do > +not provide a way to write to it. Instead of setting the hardware clock, write > +the difference between hardware and system clock to a file; when getting the > +hardware clock, add the offset from this file to obtain the correct time. > +.TP > .BR \-V , \ \-\-version > Display version information and exit. > .TP > diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c > index e780158..c7deab9 100644 > --- a/sys-utils/hwclock.c > +++ b/sys-utils/hwclock.c > @@ -98,6 +98,7 @@ struct clock_ops *ur; > #define MAX_DRIFT 2145.0 > > const char *adj_file_name = NULL; > +const char *offset_file_name = NULL; > > struct adjtime { > /* > @@ -234,6 +235,35 @@ hw_clock_is_utc(const bool utc, const bool local_opt, > return ret; > } > > +static int read_offset(struct timeval *offset) > +{ > + FILE *f; > + int rc; > + f = fopen(offset_file_name, "r"); > + if (!f) > + return -errno; > + > + rc = fread(offset, sizeof(*offset), 1, f); > + fclose(f); > + > + return rc == 1 ? 0 : -EINVAL; > +} > + > +static int write_offset(struct timeval offset) > +{ > + FILE *f; > + int rc; > + f = fopen(offset_file_name, "w"); > + if (!f) > + return -errno; > + > + rc = fwrite(&offset, sizeof(offset), 1, f); > + fclose(f); > + > + return rc == 1 ? 0 : -EINVAL; > +} > + > + > /* > * Read the adjustment parameters out of the /etc/adjtime file. > * > @@ -1290,6 +1320,8 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, > bool no_auth; > /* The time at which we read the Hardware Clock */ > struct timeval read_time; > + /* The offset between system time and hardware time */ > + struct timeval offset = {0}; > /* > * The Hardware Clock gives us a valid time, or at > * least something close enough to fool mktime(). > @@ -1320,6 +1352,11 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, > adjtime.dirty = FALSE; > } > > + if ((hctosys || show) && offset_file_name) > + { > + read_offset(&offset); > + } > + > universal = hw_clock_is_utc(utc, local_opt, adjtime); > > if ((set || systohc || adjust) && > @@ -1328,7 +1365,8 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, > adjtime.dirty = TRUE; > } > > - if (show || adjust || hctosys || (!noadjfile && !systz && !predict)) { > + if (show || adjust || hctosys || (!noadjfile && !systz && !predict) || > + offset_file_name) { > /* data from HW-clock are required */ > rc = synchronize_to_clock_tick(); > > @@ -1358,8 +1396,20 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, > } > > if (show) { > - display_time(hclock_valid, hclocktime, > + display_time(hclock_valid, hclocktime + offset.tv_sec, > time_diff(read_time, startup_time)); > + } else if (set && offset_file_name) { > + if (!hclock_valid) { > + printf(_("Hardware clock invalid, not writing offset.\n")); > + } else { > + offset.tv_sec = set_time - hclocktime; > + rc = write_offset(offset); > + if (rc) { > + printf(_("Unable to write offset: %s."), strerror(-rc)); > + return rc; > + } > + } > + > } else if (set) { > set_hardware_clock_exact(set_time, startup_time, > universal, testing); > @@ -1371,6 +1421,18 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, > } else if (adjust) { > do_adjustment(&adjtime, hclock_valid, > hclocktime, read_time, universal, testing); > + } else if (systohc && offset_file_name) { > + if (!hclock_valid) { > + printf(_("Hardware clock invalid, not writing offset.\n")); > + } else { > + gettimeofday(&offset, NULL); > + offset.tv_sec -= hclocktime; > + rc = write_offset(offset); > + if (rc) { > + printf(_("Unable to write offset: %s."), strerror(-rc)); > + return rc; > + } > + } > } else if (systohc) { > struct timeval nowtime, reftime; > /* > @@ -1390,6 +1452,17 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, > reftime.tv_sec, > hclock_valid, hclocktime, (double) > read_time.tv_usec / 1E6); > + } else if (hctosys && offset_file_name) { > + if (!hclock_valid) { > + printf(_("Hardware clock invalid, not setting time.\n")); > + } else { > + offset.tv_sec += hclocktime; > + rc = settimeofday(&offset, NULL); > + if (rc) { > + printf(_("Unable to set system clock.\n")); > + return rc; > + } > + } > } else if (hctosys) { > rc = set_system_clock(hclock_valid, hclocktime, testing); > if (rc) { > @@ -1547,6 +1620,7 @@ static void out_version(void) > printf(UTIL_LINUX_VERSION); > } > > +#define DEFAULT_OFFSET_FILE "/etc/time_offset" > /* > * usage - Output (error and) usage information > * > @@ -1577,6 +1651,10 @@ static void usage(const char *fmt, ...) > " --adjust adjust the RTC to account for systematic drift since\n" > " the clock was last set or adjusted\n"), usageto); > fputs(_(" -c, --compare periodically compare the system clock with the CMOS clock\n"), usageto); > + fprintf(usageto, > + _(" --offset [file] instead of setting the clock, write an offset to file.\n" > + " when reading the time, add this offset to the hardware time.\n" > + " (default: %s)\n"), DEFAULT_OFFSET_FILE); > #ifdef __linux__ > fputs(_(" --getepoch print out the kernel's hardware clock epoch value\n" > " --setepoch set the kernel's hardware clock epoch value to the \n" > @@ -1653,6 +1731,7 @@ int main(int argc, char **argv) > /* Long only options. */ > enum { > OPT_ADJFILE = CHAR_MAX + 1, > + OPT_OFFSET, > OPT_BADYEAR, > OPT_DATE, > OPT_DIRECTISA, > @@ -1698,6 +1777,7 @@ int main(int argc, char **argv) > {"test", 0, 0, OPT_TEST}, > {"date", 1, 0, OPT_DATE}, > {"epoch", 1, 0, OPT_EPOCH}, > + {"offset", 2, 0, OPT_OFFSET}, > #ifdef __linux__ > {"rtc", 1, 0, 'f'}, > #endif > @@ -1837,6 +1917,10 @@ int main(int argc, char **argv) > case OPT_PREDICT_HC: > predict = TRUE; /* --predict-hc */ > break; > + case OPT_OFFSET: > + offset_file_name = /* --offset */ > + optarg ? optarg : DEFAULT_OFFSET_FILE; > + break; > #ifdef __linux__ > case 'f': > rtc_dev_name = optarg; /* --rtc */ > -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html