summaryrefslogtreecommitdiffstats
path: root/hwclock/hwclock.c
diff options
context:
space:
mode:
authorSami Kerola2011-07-24 17:35:43 +0200
committerSami Kerola2011-07-26 17:27:18 +0200
commitef71b8f1128b72bf072f1bd0a306b1bb06781a40 (patch)
tree14c87f9c2a58cb8f1a95e98fa7793dbb5fb2b502 /hwclock/hwclock.c
parenthwclock: remove misleading information (diff)
downloadkernel-qcow2-util-linux-ef71b8f1128b72bf072f1bd0a306b1bb06781a40.tar.gz
kernel-qcow2-util-linux-ef71b8f1128b72bf072f1bd0a306b1bb06781a40.tar.xz
kernel-qcow2-util-linux-ef71b8f1128b72bf072f1bd0a306b1bb06781a40.zip
hwclock: coding style clean up
Despide amount of the change this change should be harmless. Everything is about indendation, comment restructuring etc not code changes. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'hwclock/hwclock.c')
-rw-r--r--hwclock/hwclock.c2453
1 files changed, 1234 insertions, 1219 deletions
diff --git a/hwclock/hwclock.c b/hwclock/hwclock.c
index 68e76b896..0c6b0f6cd 100644
--- a/hwclock/hwclock.c
+++ b/hwclock/hwclock.c
@@ -8,35 +8,24 @@
*
* Major rewrite by Bryan Henderson <bryanh@giraffe-data.com>, 96.09.19.
* The new program is called hwclock. New features:
- * - You can set the hardware clock without also modifying the system clock.
- * - You can read and set the clock with finer than 1 second precision.
- * - When you set the clock, hwclock automatically refigures the drift
- * rate, based on how far off the clock was before you set it.
+ *
+ * - You can set the hardware clock without also modifying the system
+ * clock.
+ * - You can read and set the clock with finer than 1 second precision.
+ * - When you set the clock, hwclock automatically refigures the drift
+ * rate, based on how far off the clock was before you set it.
*
* Reshuffled things, added sparc code, and re-added alpha stuff
* by David Mosberger <davidm@azstarnet.com>
* and Jay Estabrook <jestabro@amt.tay1.dec.com>
* and Martin Ostermann <ost@coments.rwth-aachen.de>, aeb@cwi.nl, 990212.
*
- * Fix for Award 2094 bug, Dave Coffin (dcoffin@shore.net) 11/12/98
+ * Fix for Award 2094 bug, Dave Coffin (dcoffin@shore.net) 11/12/98
* Change of local time handling, Stefan Ring <e9725446@stud3.tuwien.ac.at>
* Change of adjtime handling, James P. Rutledge <ao112@rgfn.epcc.edu>.
*
* Distributed under GPL
*/
-
-/*
- * clock [-u] -r - read hardware clock
- * clock [-u] -w - write hardware clock from system time
- * clock [-u] -s - set system time from hardware clock
- * clock [-u] -a - set system time from hardware clock, adjust the time
- * to correct for systematic error, and write it back to
- * the hardware clock
- * -u indicates cmos clock is kept in universal time
- * -A indicates cmos clock is kept in Alpha ARC console time (0 == 1980)
- * -J indicates we're dealing with a Jensen (early DEC Alpha PC)
- */
-
/*
* Explanation of `adjusting' (Rob Hooft):
*
@@ -49,23 +38,23 @@
* to determine the correction, and to save its data. In this file are
* three numbers:
*
- * 1) the correction in seconds per day. (So if your clock runs 5
- * seconds per day fast, the first number should read -5.0)
- * 2) the number of seconds since 1/1/1970 the last time the program
- * was used
- * 3) the remaining part of a second which was leftover after the last
- * adjustment
+ * 1) the correction in seconds per day. (So if your clock runs 5
+ * seconds per day fast, the first number should read -5.0)
+ * 2) the number of seconds since 1/1/1970 the last time the program
+ * was used
+ * 3) the remaining part of a second which was leftover after the last
+ * adjustment
*
* Installation and use of this program:
*
- * a) create a file '/etc/adjtime' containing as the first and only line:
- * '0.0 0 0.0'
- * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in
- * universal or local time. This updates the second number.
- * c) set your system time using the 'date' command.
- * d) update your cmos time using 'clock -wu' or 'clock -w'
- * e) replace the first number in /etc/adjtime by your correction.
- * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local'
+ * a) create a file '/etc/adjtime' containing as the first and only
+ * line: '0.0 0 0.0'
+ * b) run 'clock -au' or 'clock -a', depending on whether your cmos is
+ * in universal or local time. This updates the second number.
+ * c) set your system time using the 'date' command.
+ * d) update your cmos time using 'clock -wu' or 'clock -w'
+ * e) replace the first number in /etc/adjtime by your correction.
+ * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local'
*/
#include <string.h>
@@ -108,115 +97,125 @@ const char *adj_file_name = NULL;
#define LASTDATE "/var/lib/lastdate"
struct adjtime {
- /* This is information we keep in the adjtime file that tells us how
- to do drift corrections. Elements are all straight from the
- adjtime file, so see documentation of that file for details.
- Exception is <dirty>, which is an indication that what's in this
- structure is not what's in the disk file (because it has been
- updated since read from the disk file).
- */
- bool dirty;
-
- /* line 1 */
- double drift_factor;
- time_t last_adj_time;
- double not_adjusted;
-
- /* line 2 */
- time_t last_calib_time;
- /* The most recent time that we set the clock from an external
- authority (as opposed to just doing a drift adjustment) */
-
- /* line 3 */
- enum a_local_utc {LOCAL, UTC, UNKNOWN} local_utc;
- /* To which time zone, local or UTC, we most recently set the
- hardware clock. */
+ /*
+ * This is information we keep in the adjtime file that tells us how
+ * to do drift corrections. Elements are all straight from the
+ * adjtime file, so see documentation of that file for details.
+ * Exception is <dirty>, which is an indication that what's in this
+ * structure is not what's in the disk file (because it has been
+ * updated since read from the disk file).
+ */
+ bool dirty;
+ /* line 1 */
+ double drift_factor;
+ time_t last_adj_time;
+ double not_adjusted;
+ /* line 2 */
+ time_t last_calib_time;
+ /*
+ * The most recent time that we set the clock from an external
+ * authority (as opposed to just doing a drift adjustment)
+ */
+ /* line 3 */
+ enum a_local_utc { LOCAL, UTC, UNKNOWN } local_utc;
+ /*
+ * To which time zone, local or UTC, we most recently set the
+ * hardware clock.
+ */
};
+
+/*
+ * We are running in debug mode, wherein we put a lot of information about
+ * what we're doing to standard output.
+ */
bool debug;
- /* We are running in debug mode, wherein we put a lot of information about
- what we're doing to standard output. */
+/* Workaround for Award 4.50g BIOS bug: keep the year in a file. */
bool badyear;
- /* Workaround for Award 4.50g BIOS bug: keep the year in a file. */
+/* User-specified epoch, used when rtc fails to return epoch. */
int epoch_option = -1;
- /* User-specified epoch, used when rtc fails to return epoch. */
/*
- * Almost all Award BIOS's made between 04/26/94 and 05/31/95
- * have a nasty bug limiting the RTC year byte to the range 94-99.
- * Any year between 2000 and 2093 gets changed to 2094, every time
- * you start the system.
- * With the --badyear option, we write the date to file and hope
- * that the file is updated at least once a year.
- * I recommend putting this command "hwclock --badyear" in the monthly
- * crontab, just to be safe. -- Dave Coffin 11/12/98
+ * Almost all Award BIOS's made between 04/26/94 and 05/31/95 have a nasty
+ * bug limiting the RTC year byte to the range 94-99. Any year between 2000
+ * and 2093 gets changed to 2094, every time you start the system.
+ *
+ * With the --badyear option, we write the date to file and hope that the
+ * file is updated at least once a year. I recommend putting this command
+ * "hwclock --badyear" in the monthly crontab, just to be safe.
+ *
+ * -- Dave Coffin 11/12/98
*/
-static void
-write_date_to_file (struct tm *tm) {
- FILE *fp;
-
- if ((fp = fopen(LASTDATE,"w"))) {
- fprintf(fp,"%02d.%02d.%04d\n", tm->tm_mday, tm->tm_mon+1,
- tm->tm_year+1900);
- fclose(fp);
- } else
- perror(LASTDATE);
+static void write_date_to_file(struct tm *tm)
+{
+ FILE *fp;
+
+ if ((fp = fopen(LASTDATE, "w"))) {
+ fprintf(fp, "%02d.%02d.%04d\n", tm->tm_mday, tm->tm_mon + 1,
+ tm->tm_year + 1900);
+ fclose(fp);
+ } else
+ perror(LASTDATE);
}
-static void
-read_date_from_file (struct tm *tm) {
- int last_mday, last_mon, last_year;
- FILE *fp;
-
- if ((fp = fopen(LASTDATE,"r"))) {
- if (fscanf (fp,"%d.%d.%d\n", &last_mday, &last_mon, &last_year) == 3) {
- tm->tm_year = last_year-1900;
- if ((tm->tm_mon << 5) + tm->tm_mday < ((last_mon-1) << 5) + last_mday)
- tm->tm_year ++;
- }
- fclose(fp);
- }
- write_date_to_file (tm);
+static void read_date_from_file(struct tm *tm)
+{
+ int last_mday, last_mon, last_year;
+ FILE *fp;
+
+ if ((fp = fopen(LASTDATE, "r"))) {
+ if (fscanf(fp, "%d.%d.%d\n", &last_mday, &last_mon, &last_year)
+ == 3) {
+ tm->tm_year = last_year - 1900;
+ if ((tm->tm_mon << 5) + tm->tm_mday <
+ ((last_mon - 1) << 5) + last_mday)
+ tm->tm_year++;
+ }
+ fclose(fp);
+ }
+ write_date_to_file(tm);
}
-double
-time_diff(struct timeval subtrahend, struct timeval subtractor) {
-/*---------------------------------------------------------------------------
- The difference in seconds between two times in "timeval" format.
-----------------------------------------------------------------------------*/
- return (subtrahend.tv_sec - subtractor.tv_sec)
- + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6;
+/*
+ * The difference in seconds between two times in "timeval" format.
+ */
+double time_diff(struct timeval subtrahend, struct timeval subtractor)
+{
+ return (subtrahend.tv_sec - subtractor.tv_sec)
+ + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6;
}
-
-static struct timeval
-time_inc(struct timeval addend, double increment) {
-/*----------------------------------------------------------------------------
- The time, in "timeval" format, which is <increment> seconds after
- the time <addend>. Of course, <increment> may be negative.
------------------------------------------------------------------------------*/
- struct timeval newtime;
-
- newtime.tv_sec = addend.tv_sec + (int) increment;
- newtime.tv_usec = addend.tv_usec + (increment - (int) increment) * 1E6;
-
- /* Now adjust it so that the microsecond value is between 0 and 1 million */
- if (newtime.tv_usec < 0) {
- newtime.tv_usec += 1E6;
- newtime.tv_sec -= 1;
- } else if (newtime.tv_usec >= 1E6) {
- newtime.tv_usec -= 1E6;
- newtime.tv_sec += 1;
- }
- return newtime;
+/*
+ * The time, in "timeval" format, which is <increment> seconds after the
+ * time <addend>. Of course, <increment> may be negative.
+ */
+static struct timeval time_inc(struct timeval addend, double increment)
+{
+ struct timeval newtime;
+
+ newtime.tv_sec = addend.tv_sec + (int)increment;
+ newtime.tv_usec = addend.tv_usec + (increment - (int)increment) * 1E6;
+
+ /*
+ * Now adjust it so that the microsecond value is between 0 and 1
+ * million.
+ */
+ if (newtime.tv_usec < 0) {
+ newtime.tv_usec += 1E6;
+ newtime.tv_sec -= 1;
+ } else if (newtime.tv_usec >= 1E6) {
+ newtime.tv_usec -= 1E6;
+ newtime.tv_sec += 1;
+ }
+ return newtime;
}
-
static bool
hw_clock_is_utc(const bool utc, const bool local_opt,
- const struct adjtime adjtime) {
+ const struct adjtime adjtime)
+{
bool ret;
if (utc)
@@ -224,7 +223,7 @@ hw_clock_is_utc(const bool utc, const bool local_opt,
else if (local_opt)
ret = FALSE; /* --localtime explicitly given */
else
- /* get info from adjtime file - default is UTC */
+ /* get info from adjtime file - default is UTC */
ret = (adjtime.local_utc != LOCAL);
if (debug)
printf(_("Assuming hardware clock is kept in %s time.\n"),
@@ -232,122 +231,120 @@ hw_clock_is_utc(const bool utc, const bool local_opt,
return ret;
}
+/*
+ * Read the adjustment parameters out of the /etc/adjtime file.
+ *
+ * Return them as the adjtime structure <*adjtime_p>. If there is no
+ * /etc/adjtime file, return defaults. If values are missing from the file,
+ * return defaults for them.
+ *
+ * return value 0 if all OK, !=0 otherwise.
+ */
+static int read_adjtime(struct adjtime *adjtime_p)
+{
+ FILE *adjfile;
+ int rc; /* local return code */
+ struct stat statbuf; /* We don't even use the contents of this. */
+ char line1[81]; /* String: first line of adjtime file */
+ char line2[81]; /* String: second line of adjtime file */
+ char line3[81]; /* String: third line of adjtime file */
+ long timeval;
+
+ rc = stat(adj_file_name, &statbuf);
+ if (rc < 0 && errno == ENOENT) {
+ /* He doesn't have a adjtime file, so we'll use defaults. */
+ adjtime_p->drift_factor = 0;
+ adjtime_p->last_adj_time = 0;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->last_calib_time = 0;
+ adjtime_p->local_utc = UNKNOWN;
+ adjtime_p->dirty = FALSE; /* don't create a zero adjfile */
+
+ return 0;
+ }
-
-static int
-read_adjtime(struct adjtime *adjtime_p) {
-/*----------------------------------------------------------------------------
- Read the adjustment parameters out of the /etc/adjtime file.
-
- Return them as the adjtime structure <*adjtime_p>.
- If there is no /etc/adjtime file, return defaults.
- If values are missing from the file, return defaults for them.
-
- return value 0 if all OK, !=0 otherwise.
-
------------------------------------------------------------------------------*/
- FILE *adjfile;
- int rc; /* local return code */
- struct stat statbuf; /* We don't even use the contents of this. */
-
- rc = stat(adj_file_name, &statbuf);
- if (rc < 0 && errno == ENOENT) {
- /* He doesn't have a adjtime file, so we'll use defaults. */
- adjtime_p->drift_factor = 0;
- adjtime_p->last_adj_time = 0;
- adjtime_p->not_adjusted = 0;
- adjtime_p->last_calib_time = 0;
- adjtime_p->local_utc = UNKNOWN;
- adjtime_p->dirty = FALSE; /* don't create a zero adjfile */
-
- return 0;
- }
-
- adjfile = fopen(adj_file_name, "r"); /* open file for reading */
- if (adjfile == NULL) {
- outsyserr("cannot open file %s", adj_file_name);
- return EX_OSFILE;
- }
-
- {
- char line1[81]; /* String: first line of adjtime file */
- char line2[81]; /* String: second line of adjtime file */
- char line3[81]; /* String: third line of adjtime file */
- long timeval;
-
- if (!fgets(line1, sizeof(line1), adjfile))
- line1[0] = '\0'; /* In case fgets fails */
- if (!fgets(line2, sizeof(line2), adjfile))
- line2[0] = '\0'; /* In case fgets fails */
- if (!fgets(line3, sizeof(line3), adjfile))
- line3[0] = '\0'; /* In case fgets fails */
-
- fclose(adjfile);
-
- /* Set defaults in case values are missing from file */
- adjtime_p->drift_factor = 0;
- adjtime_p->last_adj_time = 0;
- adjtime_p->not_adjusted = 0;
- adjtime_p->last_calib_time = 0;
- timeval = 0;
-
- sscanf(line1, "%lf %ld %lf",
- &adjtime_p->drift_factor,
- &timeval,
- &adjtime_p->not_adjusted);
- adjtime_p->last_adj_time = timeval;
-
- sscanf(line2, "%ld", &timeval);
- adjtime_p->last_calib_time = timeval;
-
- if (!strcmp(line3, "UTC\n"))
- adjtime_p->local_utc = UTC;
- else if (!strcmp(line3, "LOCAL\n"))
- adjtime_p->local_utc = LOCAL;
- else {
- adjtime_p->local_utc = UNKNOWN;
- if (line3[0]) {
- fprintf(stderr,
- _("%s: Warning: unrecognized third line in adjtime file\n"),
- MYNAME);
- fprintf(stderr, _("(Expected: `UTC' or `LOCAL' or nothing.)\n"));
+ adjfile = fopen(adj_file_name, "r"); /* open file for reading */
+ if (adjfile == NULL) {
+ outsyserr("cannot open file %s", adj_file_name);
+ return EX_OSFILE;
}
- }
- }
- adjtime_p->dirty = FALSE;
-
- if (debug) {
- printf(_("Last drift adjustment done at %ld seconds after 1969\n"),
- (long) adjtime_p->last_adj_time);
- printf(_("Last calibration done at %ld seconds after 1969\n"),
- (long) adjtime_p->last_calib_time);
- printf(_("Hardware clock is on %s time\n"),
- (adjtime_p->local_utc == LOCAL) ? _("local") :
- (adjtime_p->local_utc == UTC) ? _("UTC") : _("unknown"));
- }
-
- return 0;
-}
-static int
-synchronize_to_clock_tick(void) {
-/*-----------------------------------------------------------------------------
- Wait until the falling edge of the Hardware Clock's update flag so
- that any time that is read from the clock immediately after we
- return will be exact.
+ if (!fgets(line1, sizeof(line1), adjfile))
+ line1[0] = '\0'; /* In case fgets fails */
+ if (!fgets(line2, sizeof(line2), adjfile))
+ line2[0] = '\0'; /* In case fgets fails */
+ if (!fgets(line3, sizeof(line3), adjfile))
+ line3[0] = '\0'; /* In case fgets fails */
+
+ fclose(adjfile);
+
+ /* Set defaults in case values are missing from file */
+ adjtime_p->drift_factor = 0;
+ adjtime_p->last_adj_time = 0;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->last_calib_time = 0;
+ timeval = 0;
+
+ sscanf(line1, "%lf %ld %lf",
+ &adjtime_p->drift_factor,
+ &timeval, &adjtime_p->not_adjusted);
+ adjtime_p->last_adj_time = timeval;
+
+ sscanf(line2, "%ld", &timeval);
+ adjtime_p->last_calib_time = timeval;
+
+ if (!strcmp(line3, "UTC\n")) {
+ adjtime_p->local_utc = UTC;
+ } else if (!strcmp(line3, "LOCAL\n")) {
+ adjtime_p->local_utc = LOCAL;
+ } else {
+ adjtime_p->local_utc = UNKNOWN;
+ if (line3[0]) {
+ fprintf(stderr,
+ _("%s: Warning: unrecognized third line in adjtime file\n"),
+ MYNAME);
+ fprintf(stderr,
+ _("(Expected: `UTC' or `LOCAL' or nothing.)\n"));
+ }
+ }
- The clock only has 1 second precision, so it gives the exact time only
- once per second, right on the falling edge of the update flag.
+ adjtime_p->dirty = FALSE;
- We wait (up to one second) either blocked waiting for an rtc device
- or in a CPU spin loop. The former is probably not very accurate.
+ if (debug) {
+ printf(_
+ ("Last drift adjustment done at %ld seconds after 1969\n"),
+ (long)adjtime_p->last_adj_time);
+ printf(_("Last calibration done at %ld seconds after 1969\n"),
+ (long)adjtime_p->last_calib_time);
+ printf(_("Hardware clock is on %s time\n"),
+ (adjtime_p->local_utc ==
+ LOCAL) ? _("local") : (adjtime_p->local_utc ==
+ UTC) ? _("UTC") : _("unknown"));
+ }
+
+ return 0;
+}
- Return 0 if it worked, nonzero if it didn't.
------------------------------------------------------------------------------*/
+/*
+ * Wait until the falling edge of the Hardware Clock's update flag so that
+ * any time that is read from the clock immediately after we return will be
+ * exact.
+ *
+ * The clock only has 1 second precision, so it gives the exact time only
+ * once per second, right on the falling edge of the update flag.
+ *
+ * We wait (up to one second) either blocked waiting for an rtc device or in
+ * a CPU spin loop. The former is probably not very accurate.
+ *
+ * Return 0 if it worked, nonzero if it didn't.
+ */
+static int synchronize_to_clock_tick(void)
+{
int rc;
- if (debug) printf(_("Waiting for clock tick...\n"));
+ if (debug)
+ printf(_("Waiting for clock tick...\n"));
rc = ur->synchronize_to_clock_tick();
@@ -361,254 +358,259 @@ synchronize_to_clock_tick(void) {
return rc;
}
-
-
+/*
+ * Convert a time in broken down format (hours, minutes, etc.) into standard
+ * unix time (seconds into epoch). Return it as *systime_p.
+ *
+ * The broken down time is argument <tm>. This broken down time is either
+ * in local time zone or UTC, depending on value of logical argument
+ * "universal". True means it is in UTC.
+ *
+ * If the argument contains values that do not constitute a valid time, and
+ * mktime() recognizes this, return *valid_p == false and *systime_p
+ * undefined. However, mktime() sometimes goes ahead and computes a
+ * fictional time "as if" the input values were valid, e.g. if they indicate
+ * the 31st day of April, mktime() may compute the time of May 1. In such a
+ * case, we return the same fictional value mktime() does as *systime_p and
+ * return *valid_p == true.
+ */
static void
mktime_tz(struct tm tm, const bool universal,
- bool *valid_p, time_t *systime_p) {
-/*-----------------------------------------------------------------------------
- Convert a time in broken down format (hours, minutes, etc.) into standard
- unix time (seconds into epoch). Return it as *systime_p.
-
- The broken down time is argument <tm>. This broken down time is either in
- local time zone or UTC, depending on value of logical argument "universal".
- True means it is in UTC.
-
- If the argument contains values that do not constitute a valid time,
- and mktime() recognizes this, return *valid_p == false and
- *systime_p undefined. However, mktime() sometimes goes ahead and
- computes a fictional time "as if" the input values were valid,
- e.g. if they indicate the 31st day of April, mktime() may compute
- the time of May 1. In such a case, we return the same fictional
- value mktime() does as *systime_p and return *valid_p == true.
-
------------------------------------------------------------------------------*/
- time_t mktime_result; /* The value returned by our mktime() call */
- char *zone; /* Local time zone name */
-
- /* We use the C library function mktime(), but since it only works on
- local time zone input, we may have to fake it out by temporarily
- changing the local time zone to UTC.
- */
- zone = getenv("TZ"); /* remember original time zone */
- if (universal) {
- /* Set timezone to UTC */
- setenv("TZ", "", TRUE);
- /* Note: tzset() gets called implicitly by the time code, but only the
- first time. When changing the environment variable, better call
- tzset() explicitly.
- */
- tzset();
- }
- mktime_result = mktime(&tm);
- if (mktime_result == -1) {
- /* This apparently (not specified in mktime() documentation) means
- the 'tm' structure does not contain valid values (however, not
- containing valid values does _not_ imply mktime() returns -1).
- */
- *valid_p = FALSE;
- *systime_p = 0;
- if (debug)
- printf(_("Invalid values in hardware clock: "
- "%4d/%.2d/%.2d %.2d:%.2d:%.2d\n"),
- tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- } else {
- *valid_p = TRUE;
- *systime_p = mktime_result;
- if (debug)
- printf(_("Hw clock time : %4d/%.2d/%.2d %.2d:%.2d:%.2d = "
- "%ld seconds since 1969\n"),
- tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, (long) *systime_p);
- }
- /* now put back the original zone. */
- if (zone) setenv("TZ", zone, TRUE);
- else unsetenv("TZ");
- tzset();
+ bool * valid_p, time_t * systime_p)
+{
+ time_t mktime_result; /* The value returned by our mktime() call */
+ char *zone; /* Local time zone name */
+
+ /*
+ * We use the C library function mktime(), but since it only works
+ * on local time zone input, we may have to fake it out by
+ * temporarily changing the local time zone to UTC.
+ */
+ zone = getenv("TZ"); /* remember original time zone */
+ if (universal) {
+ /* Set timezone to UTC */
+ setenv("TZ", "", TRUE);
+ /*
+ * Note: tzset() gets called implicitly by the time code,
+ * but only the first time. When changing the environment
+ * variable, better call tzset() explicitly.
+ */
+ tzset();
+ }
+ mktime_result = mktime(&tm);
+ if (mktime_result == -1) {
+ /*
+ * This apparently (not specified in mktime() documentation)
+ * means the 'tm' structure does not contain valid values
+ * (however, not containing valid values does _not_ imply
+ * mktime() returns -1).
+ */
+ *valid_p = FALSE;
+ *systime_p = 0;
+ if (debug)
+ printf(_("Invalid values in hardware clock: "
+ "%4d/%.2d/%.2d %.2d:%.2d:%.2d\n"),
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ } else {
+ *valid_p = TRUE;
+ *systime_p = mktime_result;
+ if (debug)
+ printf(_
+ ("Hw clock time : %4d/%.2d/%.2d %.2d:%.2d:%.2d = "
+ "%ld seconds since 1969\n"), tm.tm_year + 1900,
+ tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
+ tm.tm_sec, (long)*systime_p);
+ }
+ /* now put back the original zone. */
+ if (zone)
+ setenv("TZ", zone, TRUE);
+ else
+ unsetenv("TZ");
+ tzset();
}
-
+/*
+ * Read the hardware clock and return the current time via <tm> argument.
+ *
+ * Use the method indicated by <method> argument to access the hardware
+ * clock.
+ */
static int
-read_hardware_clock(const bool universal, bool *valid_p, time_t *systime_p){
-/*----------------------------------------------------------------------------
- Read the hardware clock and return the current time via <tm> argument.
-
- Use the method indicated by <method> argument to access the hardware clock.
------------------------------------------------------------------------------*/
- struct tm tm;
- int err;
+read_hardware_clock(const bool universal, bool * valid_p, time_t * systime_p)
+{
+ struct tm tm;
+ int err;
- err = ur->read_hardware_clock(&tm);
- if (err)
- return err;
+ err = ur->read_hardware_clock(&tm);
+ if (err)
+ return err;
- if (badyear)
- read_date_from_file(&tm);
+ if (badyear)
+ read_date_from_file(&tm);
- if (debug)
- printf (_("Time read from Hardware Clock: %4d/%.2d/%.2d %02d:%02d:%02d\n"),
- tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- mktime_tz(tm, universal, valid_p, systime_p);
+ if (debug)
+ printf(_
+ ("Time read from Hardware Clock: %4d/%.2d/%.2d %02d:%02d:%02d\n"),
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
+ tm.tm_min, tm.tm_sec);
+ mktime_tz(tm, universal, valid_p, systime_p);
- return 0;
+ return 0;
}
-
+/*
+ * Set the Hardware Clock to the time <newtime>, in local time zone or UTC,
+ * according to <universal>.
+ */
static void
set_hardware_clock(const time_t newtime,
- const bool universal,
- const bool testing) {
-/*----------------------------------------------------------------------------
- Set the Hardware Clock to the time <newtime>, in local time zone or UTC,
- according to <universal>.
-----------------------------------------------------------------------------*/
- struct tm new_broken_time;
- /* Time to which we will set Hardware Clock, in broken down format, in
- the time zone of caller's choice
- */
-
- if (universal)
- new_broken_time = *gmtime(&newtime);
- else
- new_broken_time = *localtime(&newtime);
-
- if (debug)
- printf(_("Setting Hardware Clock to %.2d:%.2d:%.2d "
- "= %ld seconds since 1969\n"),
- new_broken_time.tm_hour, new_broken_time.tm_min,
- new_broken_time.tm_sec, (long) newtime);
-
- if (testing)
- printf(_("Clock not changed - testing only.\n"));
- else {
- if (badyear) {
- /*
- * Write the real year to a file, then write a fake year
- * between 1995 and 1998 to the RTC. This way, Award BIOS boots
- * on 29 Feb 2000 thinking that it's 29 Feb 1996.
- */
- write_date_to_file (&new_broken_time);
- new_broken_time.tm_year = 95 + ((new_broken_time.tm_year+1) & 3);
- }
- ur->set_hardware_clock(&new_broken_time);
- }
-}
+ const bool universal, const bool testing)
+{
+ struct tm new_broken_time;
+ /*
+ * Time to which we will set Hardware Clock, in broken down format,
+ * in the time zone of caller's choice
+ */
+
+ if (universal)
+ new_broken_time = *gmtime(&newtime);
+ else
+ new_broken_time = *localtime(&newtime);
+ if (debug)
+ printf(_("Setting Hardware Clock to %.2d:%.2d:%.2d "
+ "= %ld seconds since 1969\n"),
+ new_broken_time.tm_hour, new_broken_time.tm_min,
+ new_broken_time.tm_sec, (long)newtime);
+ if (testing)
+ printf(_("Clock not changed - testing only.\n"));
+ else {
+ if (badyear) {
+ /*
+ * Write the real year to a file, then write a fake
+ * year between 1995 and 1998 to the RTC. This way,
+ * Award BIOS boots on 29 Feb 2000 thinking that
+ * it's 29 Feb 1996.
+ */
+ write_date_to_file(&new_broken_time);
+ new_broken_time.tm_year =
+ 95 + ((new_broken_time.tm_year + 1) & 3);
+ }
+ ur->set_hardware_clock(&new_broken_time);
+ }
+}
+/*
+ * Set the Hardware Clock to the time "sethwtime", in local time zone or
+ * UTC, according to "universal".
+ *
+ * Wait for a fraction of a second so that "sethwtime" is the value of the
+ * Hardware Clock as of system time "refsystime", which is in the past. For
+ * 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.
+ *
+ * (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
+ * that there are two independent time scales here).
+ *
+ * This function ought to be able to accept set times as fractional times.
+ * Idea for future enhancement.
+ */
static void
set_hardware_clock_exact(const time_t sethwtime,
- const struct timeval refsystime,
- const bool universal,
- const bool testing) {
-/*----------------------------------------------------------------------------
- Set the Hardware Clock to the time "sethwtime", in local time zone or UTC,
- according to "universal".
-
- Wait for a fraction of a second so that "sethwtime" is the value of
- the Hardware Clock as of system time "refsystime", which is in the past.
- For 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.
-
- (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 that there are two independent time scales here).
-
- This function ought to be able to accept set times as fractional times.
- Idea for future enhancement.
------------------------------------------------------------------------------*/
-
- time_t newhwtime;
- struct timeval beginsystime, nowsystime;
- double tdiff;
+ const struct timeval refsystime,
+ const bool universal, const bool testing)
+{
+ time_t newhwtime;
+ struct timeval beginsystime, nowsystime;
+ double tdiff;
time_resync:
- gettimeofday(&beginsystime, NULL);
- tdiff = time_diff(beginsystime, refsystime);
- newhwtime = sethwtime + (int) (tdiff + 0.5);
- if (debug)
- printf(_("Time elapsed since reference time has been %.6f seconds.\n"
- "Delaying further to reach the new time.\n"), tdiff);
-
- /*
- * Now delay some more until Hardware Clock time newhwtime arrives. The 0.5 s
- * is because the Hardware Clock always sets to your set time plus 500 ms
- * (because it is designed to update to the next second precisely 500 ms
- * after you finish the setting).
- */
- do {
- gettimeofday(&nowsystime, NULL);
- tdiff = time_diff(nowsystime, beginsystime);
- if (tdiff < 0)
- goto time_resync; /* probably backward time reset */
- if (tdiff > 0.1)
- goto time_resync; /* probably forward time reset */
- beginsystime = nowsystime;
- tdiff = time_diff(nowsystime, refsystime);
- } while (newhwtime == sethwtime + (int) (tdiff + 0.5));
-
- set_hardware_clock(newhwtime, universal, testing);
+ gettimeofday(&beginsystime, NULL);
+ tdiff = time_diff(beginsystime, refsystime);
+ newhwtime = sethwtime + (int)(tdiff + 0.5);
+ if (debug)
+ printf(_
+ ("Time elapsed since reference time has been %.6f seconds.\n"
+ "Delaying further to reach the new time.\n"), tdiff);
+
+ /*
+ * Now delay some more until Hardware Clock time newhwtime arrives.
+ * The 0.5 s is because the Hardware Clock always sets to your set
+ * time plus 500 ms (because it is designed to update to the next
+ * second precisely 500 ms after you finish the setting).
+ */
+ do {
+ gettimeofday(&nowsystime, NULL);
+ tdiff = time_diff(nowsystime, beginsystime);
+ if (tdiff < 0)
+ goto time_resync; /* probably backward time reset */
+ if (tdiff > 0.1)
+ goto time_resync; /* probably forward time reset */
+ beginsystime = nowsystime;
+ tdiff = time_diff(nowsystime, refsystime);
+ } while (newhwtime == sethwtime + (int)(tdiff + 0.5));
+
+ set_hardware_clock(newhwtime, universal, testing);
}
-
-
+/*
+ * Put the time "systime" on standard output in display format. Except if
+ * hclock_valid == false, just tell standard output that we don't know what
+ * time it is.
+ *
+ * Include in the output the adjustment "sync_duration".
+ */
static void
display_time(const bool hclock_valid, const time_t systime,
- const double sync_duration) {
-/*----------------------------------------------------------------------------
- Put the time "systime" on standard output in display format.
- Except if hclock_valid == false, just tell standard output that we don't
- know what time it is.
-
- Include in the output the adjustment "sync_duration".
------------------------------------------------------------------------------*/
- if (!hclock_valid)
- fprintf(stderr, _("The Hardware Clock registers contain values that are "
- "either invalid (e.g. 50th day of month) or beyond the range "
- "we can handle (e.g. Year 2095).\n"));
- else {
- struct tm *lt;
- char *format = "%c";
- char ctime_now[200];
-
- lt = localtime(&systime);
- strftime(ctime_now, sizeof(ctime_now), format, lt);
- printf(_("%s %.6f seconds\n"), ctime_now, -(sync_duration));
- }
-}
-
-
-
-static int
-interpret_date_string(const char *date_opt, time_t * const time_p) {
-/*----------------------------------------------------------------------------
- Interpret the value of the --date option, which is something like
- "13:05:01". In fact, it can be any of the myriad ASCII strings that specify
- a time which the "date" program can understand. The date option value in
- question is our "dateopt" argument.
-
- The specified time is in the local time zone.
-
- Our output, "*time_p", is a seconds-into-epoch time.
+ const double sync_duration)
+{
+ if (!hclock_valid)
+ fprintf(stderr,
+ _
+ ("The Hardware Clock registers contain values that are "
+ "either invalid (e.g. 50th day of month) or beyond the range "
+ "we can handle (e.g. Year 2095).\n"));
+ else {
+ struct tm *lt;
+ char *format = "%c";
+ char ctime_now[200];
- We use the "date" program to interpret the date string. "date" must be
- runnable by issuing the command "date" to the /bin/sh shell. That means
- in must be in the current PATH.
+ lt = localtime(&systime);
+ strftime(ctime_now, sizeof(ctime_now), format, lt);
+ printf(_("%s %.6f seconds\n"), ctime_now, -(sync_duration));
+ }
+}
- If anything goes wrong (and many things can), we return return code
- 10 and arbitrary *time_p. Otherwise, return code is 0 and *time_p
- is valid.
-----------------------------------------------------------------------------*/
+/*
+ * Interpret the value of the --date option, which is something like
+ * "13:05:01". In fact, it can be any of the myriad ASCII strings that
+ * specify a time which the "date" program can understand. The date option
+ * value in question is our "dateopt" argument.
+ *
+ * The specified time is in the local time zone.
+ *
+ * Our output, "*time_p", is a seconds-into-epoch time.
+ *
+ * We use the "date" program to interpret the date string. "date" must be
+ * runnable by issuing the command "date" to the /bin/sh shell. That means
+ * in must be in the current PATH.
+ *
+ * If anything goes wrong (and many things can), we return return code 10
+ * and arbitrary *time_p. Otherwise, return code is 0 and *time_p is valid.
+ */
+static int interpret_date_string(const char *date_opt, time_t * const time_p)
+{
FILE *date_child_fp;
char date_resp[100];
- const char magic[]="seconds-into-epoch=";
+ const char magic[] = "seconds-into-epoch=";
char date_command[100];
- int retcode; /* our eventual return code */
- int rc; /* local return code */
+ int retcode; /* our eventual return code */
+ int rc; /* local return code */
if (date_opt == NULL) {
fprintf(stderr, _("No --date option specified.\n"));
@@ -624,8 +626,9 @@ interpret_date_string(const char *date_opt, time_t * const time_p) {
/* Quotes in date_opt would ruin the date command we construct. */
if (strchr(date_opt, '"') != NULL) {
fprintf(stderr,
- _("The value of the --date option is not a valid date.\n"
- "In particular, it contains quotation marks.\n"));
+ _
+ ("The value of the --date option is not a valid date.\n"
+ "In particular, it contains quotation marks.\n"));
return 12;
}
@@ -642,10 +645,10 @@ interpret_date_string(const char *date_opt, time_t * const time_p) {
}
if (!fgets(date_resp, sizeof(date_resp), date_child_fp))
- date_resp[0] = '\0'; /* in case fgets fails */
+ date_resp[0] = '\0'; /* in case fgets fails */
if (debug)
printf(_("response from date command = %s\n"), date_resp);
- if (strncmp(date_resp, magic, sizeof(magic)-1) != 0) {
+ if (strncmp(date_resp, magic, sizeof(magic) - 1) != 0) {
fprintf(stderr, _("The date command issued by %s returned "
"unexpected results.\n"
"The command was:\n %s\n"
@@ -654,7 +657,7 @@ interpret_date_string(const char *date_opt, time_t * const time_p) {
retcode = 8;
} else {
long seconds_since_epoch;
- rc = sscanf(date_resp + sizeof(magic)-1, "%ld",
+ rc = sscanf(date_resp + sizeof(magic) - 1, "%ld",
&seconds_since_epoch);
if (rc < 1) {
fprintf(stderr,
@@ -671,7 +674,7 @@ interpret_date_string(const char *date_opt, time_t * const time_p) {
if (debug)
printf(_("date string %s equates to "
"%ld seconds since 1969.\n"),
- date_opt, (long) *time_p);
+ date_opt, (long)*time_p);
}
}
pclose(date_child_fp);
@@ -679,173 +682,181 @@ interpret_date_string(const char *date_opt, time_t * const time_p) {
return retcode;
}
-
-
+/*
+ * Set the System Clock to time 'newtime'.
+ *
+ * Also set the kernel time zone value to the value indicated by the TZ
+ * environment variable and/or /usr/lib/zoneinfo/, interpreted as tzset()
+ * would interpret them.
+ *
+ * EXCEPT: if hclock_valid is false, just issue an error message saying
+ * there is no valid time in the Hardware Clock to which to set the system
+ * time.
+ *
+ * If 'testing' is true, don't actually update anything -- just say we would
+ * have.
+ */
static int
set_system_clock(const bool hclock_valid, const time_t newtime,
- const bool testing) {
-/*----------------------------------------------------------------------------
- Set the System Clock to time 'newtime'.
-
- Also set the kernel time zone value to the value indicated by the
- TZ environment variable and/or /usr/lib/zoneinfo/, interpreted as
- tzset() would interpret them.
-
- EXCEPT: if hclock_valid is false, just issue an error message
- saying there is no valid time in the Hardware Clock to which to set
- the system time.
-
- If 'testing' is true, don't actually update anything -- just say we
- would have.
------------------------------------------------------------------------------*/
- int retcode;
-
- if (!hclock_valid) {
- fprintf(stderr, _("The Hardware Clock does not contain a valid time, so "
- "we cannot set the System Time from it.\n"));
- retcode = 1;
- } else {
- struct timeval tv;
- struct tm *broken;
- int minuteswest;
- int rc;
-
- tv.tv_sec = newtime;
- tv.tv_usec = 0;
-
- broken = localtime(&newtime);
+ const bool testing)
+{
+ int retcode;
+
+ if (!hclock_valid) {
+ fprintf(stderr,
+ _
+ ("The Hardware Clock does not contain a valid time, so "
+ "we cannot set the System Time from it.\n"));
+ retcode = 1;
+ } else {
+ struct timeval tv;
+ struct tm *broken;
+ int minuteswest;
+ int rc;
+
+ tv.tv_sec = newtime;
+ tv.tv_usec = 0;
+
+ broken = localtime(&newtime);
#ifdef HAVE_TM_GMTOFF
- minuteswest = -broken->tm_gmtoff/60; /* GNU extension */
+ minuteswest = -broken->tm_gmtoff / 60; /* GNU extension */
#else
- minuteswest = timezone/60;
- if (broken->tm_isdst)
- minuteswest -= 60;
+ minuteswest = timezone / 60;
+ if (broken->tm_isdst)
+ minuteswest -= 60;
#endif
- if (debug) {
- printf(_("Calling settimeofday:\n"));
- printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"),
- (long) tv.tv_sec, (long) tv.tv_usec);
- printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest);
- }
- if (testing) {
- printf(_("Not setting system clock because running in test mode.\n"));
- retcode = 0;
- } else {
- const struct timezone tz = { minuteswest, 0 };
-
- rc = settimeofday(&tv, &tz);
- if (rc) {
- if (errno == EPERM) {
- fprintf(stderr,
- _("Must be superuser to set system clock.\n"));
- retcode = EX_NOPERM;
- } else {
- outsyserr(_("settimeofday() failed"));
- retcode = 1;
- }
- } else retcode = 0;
- }
- }
- return retcode;
+ if (debug) {
+ printf(_("Calling settimeofday:\n"));
+ printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"),
+ (long)tv.tv_sec, (long)tv.tv_usec);
+ printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest);
+ }
+ if (testing) {
+ printf(_
+ ("Not setting system clock because running in test mode.\n"));
+ retcode = 0;
+ } else {
+ const struct timezone tz = { minuteswest, 0 };
+
+ rc = settimeofday(&tv, &tz);
+ if (rc) {
+ if (errno == EPERM) {
+ fprintf(stderr,
+ _
+ ("Must be superuser to set system clock.\n"));
+ retcode = EX_NOPERM;
+ } else {
+ outsyserr(_("settimeofday() failed"));
+ retcode = 1;
+ }
+ } else
+ retcode = 0;
+ }
+ }
+ return retcode;
}
+/*
+ * Reset the System Clock from local time to UTC, based on its current value
+ * and the timezone unless universal is TRUE.
+ *
+ * Also set the kernel time zone value to the value indicated by the TZ
+ * environment variable and/or /usr/lib/zoneinfo/, interpreted as tzset()
+ * would interpret them.
+ *
+ * If 'testing' is true, don't actually update anything -- just say we would
+ * have.
+ */
+static int set_system_clock_timezone(const bool universal, const bool testing)
+{
+ int retcode;
+ struct timeval tv;
+ struct tm *broken;
+ int minuteswest;
+ int rc;
+
+ gettimeofday(&tv, NULL);
+ if (debug) {
+ struct tm broken_time;
+ char ctime_now[200];
+
+ broken_time = *gmtime(&tv.tv_sec);
+ strftime(ctime_now, sizeof(ctime_now), "%Y/%m/%d %H:%M:%S",
+ &broken_time);
+ printf(_("Current system time: %ld = %s\n"), (long)tv.tv_sec,
+ ctime_now);
+ }
-static int
-set_system_clock_timezone(const bool universal, const bool testing) {
-/*----------------------------------------------------------------------------
- Reset the System Clock from local time to UTC, based on its current
- value and the timezone unless universal is TRUE.
-
- Also set the kernel time zone value to the value indicated by the
- TZ environment variable and/or /usr/lib/zoneinfo/, interpreted as
- tzset() would interpret them.
-
- If 'testing' is true, don't actually update anything -- just say we
- would have.
------------------------------------------------------------------------------*/
- int retcode;
- struct timeval tv;
- struct tm *broken;
- int minuteswest;
- int rc;
-
- gettimeofday(&tv, NULL);
- if (debug) {
- struct tm broken_time;
- char ctime_now[200];
-
- broken_time = *gmtime(&tv.tv_sec);
- strftime(ctime_now, sizeof(ctime_now), "%Y/%m/%d %H:%M:%S", &broken_time);
- printf(_("Current system time: %ld = %s\n"), (long) tv.tv_sec, ctime_now);
- }
-
- broken = localtime(&tv.tv_sec);
+ broken = localtime(&tv.tv_sec);
#ifdef HAVE_TM_GMTOFF
- minuteswest = -broken->tm_gmtoff/60; /* GNU extension */
+ minuteswest = -broken->tm_gmtoff / 60; /* GNU extension */
#else
- minuteswest = timezone/60;
- if (broken->tm_isdst)
- minuteswest -= 60;
+ minuteswest = timezone / 60;
+ if (broken->tm_isdst)
+ minuteswest -= 60;
#endif
- gettimeofday(&tv, NULL);
- if (!universal)
- tv.tv_sec += minuteswest * 60;
-
- if (debug) {
- struct tm broken_time;
- char ctime_now[200];
-
- broken_time = *gmtime(&tv.tv_sec);
- strftime(ctime_now, sizeof(ctime_now), "%Y/%m/%d %H:%M:%S", &broken_time);
-
- printf(_("Calling settimeofday:\n"));
- printf(_("\tUTC: %s\n"), ctime_now);
- printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"),
- (long) tv.tv_sec, (long) tv.tv_usec);
- printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest);
- }
- if (testing) {
- printf(_("Not setting system clock because running in test mode.\n"));
- retcode = 0;
- } else {
- const struct timezone tz = { minuteswest, 0 };
-
- rc = settimeofday(&tv, &tz);
- if (rc) {
- if (errno == EPERM) {
- fprintf(stderr,
- _("Must be superuser to set system clock.\n"));
- retcode = EX_NOPERM;
- } else {
- outsyserr(_("settimeofday() failed"));
- retcode = 1;
- }
- } else retcode = 0;
- }
- return retcode;
-}
+ gettimeofday(&tv, NULL);
+ if (!universal)
+ tv.tv_sec += minuteswest * 60;
+ if (debug) {
+ struct tm broken_time;
+ char ctime_now[200];
+
+ broken_time = *gmtime(&tv.tv_sec);
+ strftime(ctime_now, sizeof(ctime_now), "%Y/%m/%d %H:%M:%S",
+ &broken_time);
+
+ printf(_("Calling settimeofday:\n"));
+ printf(_("\tUTC: %s\n"), ctime_now);
+ printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"),
+ (long)tv.tv_sec, (long)tv.tv_usec);
+ printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest);
+ }
+ if (testing) {
+ printf(_
+ ("Not setting system clock because running in test mode.\n"));
+ retcode = 0;
+ } else {
+ const struct timezone tz = { minuteswest, 0 };
+ rc = settimeofday(&tv, &tz);
+ if (rc) {
+ if (errno == EPERM) {
+ fprintf(stderr,
+ _
+ ("Must be superuser to set system clock.\n"));
+ retcode = EX_NOPERM;
+ } else {
+ outsyserr(_("settimeofday() failed"));
+ retcode = 1;
+ }
+ } else
+ retcode = 0;
+ }
+ return retcode;
+}
+
+/*
+ * Update the drift factor in <*adjtime_p> to reflect the fact that the
+ * Hardware Clock was calibrated to <nowtime> and before that was set to
+ * <hclocktime>.
+ *
+ * We record in the adjtime file the time at which we last calibrated the
+ * clock so we can compute the drift rate each time we calibrate.
+ *
+ * EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set
+ * before to anything meaningful and regular adjustments have not been done,
+ * so don't adjust the drift factor.
+ */
static void
adjust_drift_factor(struct adjtime *adjtime_p,
- const time_t nowtime,
- const bool hclock_valid,
- const time_t hclocktime,
- const double sync_delay) {
-/*------------------------------------------------------------------------
- Update the drift factor in <*adjtime_p> to reflect the fact that the
- Hardware Clock was calibrated to <nowtime> and before that was set
- to <hclocktime>.
-
- We record in the adjtime file the time at which we last calibrated
- the clock so we can compute the drift rate each time we calibrate.
-
- EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set
- before to anything meaningful and regular adjustments have not been
- done, so don't adjust the drift factor.
- ------------------------------------------------------------------------*/
+ const time_t nowtime,
+ const bool hclock_valid,
+ const time_t hclocktime, const double sync_delay)
+{
if (!hclock_valid) {
if (debug)
printf(_("Not adjusting drift factor because the "
@@ -867,9 +878,9 @@ adjust_drift_factor(struct adjtime *adjtime_p,
* At adjustment time we adjust the hardware clock according
* to the contents of /etc/adjtime.
*
- * At calibration time we set the hardware clock and
- * update /etc/adjtime, that is, for each calibration
- * (except the first) we also do an adjustment.
+ * At calibration time we set the hardware clock and update
+ * /etc/adjtime, that is, for each calibration (except the
+ * first) we also do an adjustment.
*
* We are now at calibration time.
*
@@ -887,21 +898,21 @@ adjust_drift_factor(struct adjtime *adjtime_p,
/* Days since last adjustment (in hardware clock time) */
adj_days = (double)(hclocktime - adjtime_p->last_adj_time)
- / sec_per_day;
+ / sec_per_day;
/* Expected drift (sec) since last adjustment */
exp_drift = adj_days * adjtime_p->drift_factor
- + adjtime_p->not_adjusted;
+ + adjtime_p->not_adjusted;
/* Uncorrected drift (sec) since last calibration */
unc_drift = (double)(nowtime - hclocktime)
- + sync_delay - exp_drift;
+ + sync_delay - exp_drift;
/* Days since last calibration (in hardware clock time) */
cal_days = ((double)(adjtime_p->last_adj_time
- - adjtime_p->last_calib_time)
+ - adjtime_p->last_calib_time)
+ adjtime_p->not_adjusted)
- / (sec_per_day * atime_per_htime) + adj_days;
+ / (sec_per_day * atime_per_htime) + adj_days;
/* Amount to add to previous drift factor */
factor_adjust = unc_drift / cal_days;
@@ -912,9 +923,8 @@ adjust_drift_factor(struct adjtime *adjtime_p,
"%f seconds/day.\n"
"Adjusting drift factor by %f seconds/day\n"),
unc_drift,
- (int) (nowtime - adjtime_p->last_calib_time),
- adjtime_p->drift_factor,
- factor_adjust);
+ (int)(nowtime - adjtime_p->last_calib_time),
+ adjtime_p->drift_factor, factor_adjust);
adjtime_p->drift_factor += factor_adjust;
}
@@ -927,383 +937,403 @@ adjust_drift_factor(struct adjtime *adjtime_p,
adjtime_p->dirty = TRUE;
}
-
-
+/*
+ * Do the drift adjustment calculation.
+ *
+ * The way we have to set the clock, we need the adjustment in two parts:
+ *
+ * 1) an integer number of seconds (return as *adjustment_p)
+ * 2) a positive fraction of a second (less than 1) (return as *retro_p)
+ *
+ * The sum of these two values is the adjustment needed. Positive means to
+ * advance the clock or insert seconds. Negative means to retard the clock
+ * or remove seconds.
+ */
static void
calculate_adjustment(const double factor,
- const time_t last_time,
- const double not_adjusted,
- const time_t systime,
- int *adjustment_p,
- double *retro_p) {
-/*----------------------------------------------------------------------------
- Do the drift adjustment calculation.
-
- The way we have to set the clock, we need the adjustment in two parts:
-
- 1) an integer number of seconds (return as *adjustment_p)
-
- 2) a positive fraction of a second (less than 1) (return as *retro_p)
-
- The sum of these two values is the adjustment needed. Positive means to
- advance the clock or insert seconds. Negative means to retard the clock
- or remove seconds.
-----------------------------------------------------------------------------*/
- double exact_adjustment;
-
- exact_adjustment = ((double) (systime - last_time)) * factor / (24 * 60 * 60)
- + not_adjusted;
- *adjustment_p = FLOOR(exact_adjustment);
-
- *retro_p = exact_adjustment - (double) *adjustment_p;
- if (debug) {
- printf (_("Time since last adjustment is %d seconds\n"),
- (int) (systime - last_time));
- printf (_("Need to insert %d seconds and refer time back "
- "%.6f seconds ago\n"),
- *adjustment_p, *retro_p);
- }
-}
-
+ const time_t last_time,
+ const double not_adjusted,
+ const time_t systime, int *adjustment_p, double *retro_p)
+{
+ double exact_adjustment;
+ exact_adjustment =
+ ((double)(systime - last_time)) * factor / (24 * 60 * 60)
+ + not_adjusted;
+ *adjustment_p = FLOOR(exact_adjustment);
-static void
-save_adjtime(const struct adjtime adjtime, const bool testing) {
-/*-----------------------------------------------------------------------------
- Write the contents of the <adjtime> structure to its disk file.
-
- But if the contents are clean (unchanged since read from disk), don't
- bother.
------------------------------------------------------------------------------*/
- char newfile[412]; /* Stuff to write to disk file */
-
- if (adjtime.dirty) {
- /* snprintf is not always available, but this is safe
- as long as libc does not use more than 100 positions for %ld or %f */
- sprintf(newfile, "%f %ld %f\n%ld\n%s\n",
- adjtime.drift_factor,
- (long) adjtime.last_adj_time,
- adjtime.not_adjusted,
- (long) adjtime.last_calib_time,
- (adjtime.local_utc == UTC) ? "UTC" : "LOCAL");
-
- if (testing) {
- printf(_("Not updating adjtime file because of testing mode.\n"));
- printf(_("Would have written the following to %s:\n%s"),
- adj_file_name, newfile);
- } else {
- FILE *adjfile;
- int err = 0;
-
- adjfile = fopen(adj_file_name, "w");
- if (adjfile == NULL) {
- outsyserr(_("Could not open file with the clock adjustment parameters "
- "in it (%s) for writing"), adj_file_name);
- err = 1;
- } else {
- if (fputs(newfile, adjfile) < 0) {
- outsyserr(_("Could not update file with the clock adjustment "
- "parameters (%s) in it"), adj_file_name);
- err = 1;
- }
- if (fclose(adjfile) < 0) {
- outsyserr(_("Could not update file with the clock adjustment "
- "parameters (%s) in it"), adj_file_name);
- err = 1;
- }
- }
- if (err)
- fprintf(stderr, _("Drift adjustment parameters not updated.\n"));
- }
- }
+ *retro_p = exact_adjustment - (double)*adjustment_p;
+ if (debug) {
+ printf(_("Time since last adjustment is %d seconds\n"),
+ (int)(systime - last_time));
+ printf(_("Need to insert %d seconds and refer time back "
+ "%.6f seconds ago\n"), *adjustment_p, *retro_p);
+ }
}
+/*
+ * Write the contents of the <adjtime> structure to its disk file.
+ *
+ * But if the contents are clean (unchanged since read from disk), don't
+ * bother.
+ */
+static void save_adjtime(const struct adjtime adjtime, const bool testing)
+{
+ char newfile[412]; /* Stuff to write to disk file */
+ if (adjtime.dirty) {
+ /*
+ * snprintf is not always available, but this is safe as
+ * long as libc does not use more than 100 positions for %ld
+ * or %f
+ */
+ sprintf(newfile, "%f %ld %f\n%ld\n%s\n",
+ adjtime.drift_factor,
+ (long)adjtime.last_adj_time,
+ adjtime.not_adjusted,
+ (long)adjtime.last_calib_time,
+ (adjtime.local_utc == UTC) ? "UTC" : "LOCAL");
+
+ if (testing) {
+ printf(_
+ ("Not updating adjtime file because of testing mode.\n"));
+ printf(_("Would have written the following to %s:\n%s"),
+ adj_file_name, newfile);
+ } else {
+ FILE *adjfile;
+ int err = 0;
+
+ adjfile = fopen(adj_file_name, "w");
+ if (adjfile == NULL) {
+ outsyserr(_
+ ("Could not open file with the clock adjustment parameters "
+ "in it (%s) for writing"),
+ adj_file_name);
+ err = 1;
+ } else {
+ if (fputs(newfile, adjfile) < 0) {
+ outsyserr(_
+ ("Could not update file with the clock adjustment "
+ "parameters (%s) in it"),
+ adj_file_name);
+ err = 1;
+ }
+ if (fclose(adjfile) < 0) {
+ outsyserr(_
+ ("Could not update file with the clock adjustment "
+ "parameters (%s) in it"),
+ adj_file_name);
+ err = 1;
+ }
+ }
+ if (err)
+ fprintf(stderr,
+ _
+ ("Drift adjustment parameters not updated.\n"));
+ }
+ }
+}
+/*
+ * Do the adjustment requested, by 1) setting the Hardware Clock (if
+ * necessary), and 2) updating the last-adjusted time in the adjtime
+ * structure.
+ *
+ * Do not update anything if the Hardware Clock does not currently present a
+ * valid time.
+ *
+ * Arguments <factor> and <last_time> are current values from the adjtime
+ * file.
+ *
+ * <hclock_valid> means the Hardware Clock contains a valid time, and that
+ * time is <hclocktime>.
+ *
+ * <read_time> is the current system time (to be precise, it is the system
+ * time at the time <hclocktime> was read, which due to computational delay
+ * could be a short time ago).
+ *
+ * <universal>: the Hardware Clock is kept in UTC.
+ *
+ * <testing>: We are running in test mode (no updating of clock).
+ *
+ * We do not bother to update the clock if the adjustment would be less than
+ * one second. This is to avoid cumulative error and needless CPU hogging
+ * (remember we use an infinite loop for some timing) if the user runs us
+ * frequently.
+ */
static void
do_adjustment(struct adjtime *adjtime_p,
- const bool hclock_valid, const time_t hclocktime,
- const struct timeval read_time,
- const bool universal, const bool testing) {
-/*---------------------------------------------------------------------------
- Do the adjustment requested, by 1) setting the Hardware Clock (if
- necessary), and 2) updating the last-adjusted time in the adjtime
- structure.
-
- Do not update anything if the Hardware Clock does not currently present
- a valid time.
-
- arguments <factor> and <last_time> are current values from the adjtime
- file.
-
- <hclock_valid> means the Hardware Clock contains a valid time, and that
- time is <hclocktime>.
-
- <read_time> is the current system time (to be precise, it is the system
- time at the time <hclocktime> was read, which due to computational delay
- could be a short time ago).
-
- <universal>: the Hardware Clock is kept in UTC.
-
- <testing>: We are running in test mode (no updating of clock).
-
- We do not bother to update the clock if the adjustment would be less than
- one second. This is to avoid cumulative error and needless CPU hogging
- (remember we use an infinite loop for some timing) if the user runs us
- frequently.
-
-----------------------------------------------------------------------------*/
- if (!hclock_valid) {
- fprintf(stderr, _("The Hardware Clock does not contain a valid time, "
- "so we cannot adjust it.\n"));
- adjtime_p->last_calib_time = 0; /* calibration startover is required */
- adjtime_p->last_adj_time = 0;
- adjtime_p->not_adjusted = 0;
- adjtime_p->dirty = TRUE;
- } else if (adjtime_p->last_adj_time == 0) {
- if (debug)
- printf(_("Not setting clock because last adjustment time is zero, "
- "so history is bad."));
- } else {
- int adjustment;
- /* Number of seconds we must insert in the Hardware Clock */
- double retro;
- /* Fraction of second we have to remove from clock after inserting
- <adjustment> whole seconds.
- */
- calculate_adjustment(adjtime_p->drift_factor,
- adjtime_p->last_adj_time,
- adjtime_p->not_adjusted,
- hclocktime,
- &adjustment, &retro);
- if (adjustment > 0 || adjustment < -1) {
- set_hardware_clock_exact(hclocktime + adjustment,
- time_inc(read_time, -retro),
- universal, testing);
- adjtime_p->last_adj_time = hclocktime + adjustment;
- adjtime_p->not_adjusted = 0;
- adjtime_p->dirty = TRUE;
- } else
- if (debug)
- printf(_("Needed adjustment is less than one second, "
- "so not setting clock.\n"));
- }
+ const bool hclock_valid, const time_t hclocktime,
+ const struct timeval read_time,
+ const bool universal, const bool testing)
+{
+ if (!hclock_valid) {
+ fprintf(stderr,
+ _("The Hardware Clock does not contain a valid time, "
+ "so we cannot adjust it.\n"));
+ adjtime_p->last_calib_time = 0; /* calibration startover is required */
+ adjtime_p->last_adj_time = 0;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->dirty = TRUE;
+ } else if (adjtime_p->last_adj_time == 0) {
+ if (debug)
+ printf(_
+ ("Not setting clock because last adjustment time is zero, "
+ "so history is bad."));
+ } else {
+ int adjustment;
+ /* Number of seconds we must insert in the Hardware Clock */
+ double retro;
+ /*
+ * Fraction of second we have to remove from clock after
+ * inserting <adjustment> whole seconds.
+ */
+ calculate_adjustment(adjtime_p->drift_factor,
+ adjtime_p->last_adj_time,
+ adjtime_p->not_adjusted,
+ hclocktime, &adjustment, &retro);
+ if (adjustment > 0 || adjustment < -1) {
+ set_hardware_clock_exact(hclocktime + adjustment,
+ time_inc(read_time, -retro),
+ universal, testing);
+ adjtime_p->last_adj_time = hclocktime + adjustment;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->dirty = TRUE;
+ } else if (debug)
+ printf(_("Needed adjustment is less than one second, "
+ "so not setting clock.\n"));
+ }
}
+static void determine_clock_access_method(const bool user_requests_ISA)
+{
+ ur = NULL;
-
-static void
-determine_clock_access_method(const bool user_requests_ISA) {
-
- ur = NULL;
-
- if (user_requests_ISA)
- ur = probe_for_cmos_clock();
+ if (user_requests_ISA)
+ ur = probe_for_cmos_clock();
#ifdef __linux__
- if (!ur)
- ur = probe_for_rtc_clock();
+ if (!ur)
+ ur = probe_for_rtc_clock();
#endif
- if (!ur)
- ur = probe_for_kd_clock();
+ if (!ur)
+ ur = probe_for_kd_clock();
- if (!ur && !user_requests_ISA)
- ur = probe_for_cmos_clock();
+ if (!ur && !user_requests_ISA)
+ ur = probe_for_cmos_clock();
- if (debug) {
- if (ur)
- printf(_("Using %s.\n"), ur->interface_name);
- else
- printf(_("No usable clock interface found.\n"));
- }
+ if (debug) {
+ if (ur)
+ printf(_("Using %s.\n"), ur->interface_name);
+ else
+ printf(_("No usable clock interface found.\n"));
+ }
}
+/*
+ * Do all the normal work of hwclock - read, set clock, etc.
+ *
+ * Issue output to stdout and error message to stderr where appropriate.
+ *
+ * Return rc == 0 if everything went OK, rc != 0 if not.
+ */
static int
manipulate_clock(const bool show, const bool adjust, const bool noadjfile,
- const bool set, const time_t set_time,
- const bool hctosys, const bool systohc, const bool systz,
- const struct timeval startup_time,
- const bool utc, const bool local_opt,
- const bool testing, const bool predict) {
-/*---------------------------------------------------------------------------
- Do all the normal work of hwclock - read, set clock, etc.
-
- Issue output to stdout and error message to stderr where appropriate.
-
- Return rc == 0 if everything went OK, rc != 0 if not.
-----------------------------------------------------------------------------*/
- struct adjtime adjtime;
- /* Contents of the adjtime file, or what they should be. */
- int rc; /* local return code */
- bool no_auth; /* User lacks necessary authorization to access the clock */
-
- if (!systz && !predict) {
- no_auth = ur->get_permissions();
- if (no_auth)
- return EX_NOPERM;
- }
-
- if (!noadjfile && (adjust || set || systohc || (!utc && !local_opt) || predict)) {
- rc = read_adjtime(&adjtime);
- if (rc)
- return rc;
- } else {
- /* A little trick to avoid reading the file if we don't have to */
- adjtime.dirty = FALSE;
- rc = 0;
- }
-
- {
- const bool universal = hw_clock_is_utc(utc, local_opt, adjtime);
-
- if ((set || systohc || adjust) &&
- (adjtime.local_utc == UTC) != universal) {
- adjtime.local_utc = universal ? UTC : LOCAL;
- adjtime.dirty = TRUE;
- }
-
- {
- struct timeval read_time;
- /* The time at which we read the Hardware Clock */
-
- bool hclock_valid = FALSE;
- /* The Hardware Clock gives us a valid time, or at least something
- close enough to fool mktime().
- */
-
- time_t hclocktime = 0;
- /* The time the hardware clock had just after we
- synchronized to its next clock tick when we started up.
- Defined only if hclock_valid is true.
- */
+ const bool set, const time_t set_time,
+ const bool hctosys, const bool systohc, const bool systz,
+ const struct timeval startup_time,
+ const bool utc, const bool local_opt,
+ const bool testing, const bool predict)
+{
+ /* Contents of the adjtime file, or what they should be. */
+ struct adjtime adjtime;
+ bool universal;
+ /* Set if user lacks necessary authorization to access the clock */
+ bool no_auth;
+ /* The time at which we read the Hardware Clock */
+ struct timeval read_time;
+ /*
+ * The Hardware Clock gives us a valid time, or at
+ * least something close enough to fool mktime().
+ */
+ bool hclock_valid = FALSE;
+ /*
+ * The time the hardware clock had just after we
+ * synchronized to its next clock tick when we
+ * started up. Defined only if hclock_valid is true.
+ */
+ time_t hclocktime = 0;
+ /* local return code */
+ int rc;
+
+ if (!systz && !predict) {
+ no_auth = ur->get_permissions();
+ if (no_auth)
+ return EX_NOPERM;
+ }
+
+ if (!noadjfile
+ && (adjust || set || systohc || (!utc && !local_opt) || predict)) {
+ rc = read_adjtime(&adjtime);
+ if (rc)
+ return rc;
+ } else {
+ /* A little trick to avoid reading the file if we don't have to */
+ adjtime.dirty = FALSE;
+ rc = 0;
+ }
+
+ universal = hw_clock_is_utc(utc, local_opt, adjtime);
+
+ if ((set || systohc || adjust) &&
+ (adjtime.local_utc == UTC) != universal) {
+ adjtime.local_utc = universal ? UTC : LOCAL;
+ adjtime.dirty = TRUE;
+ }
if (show || adjust || hctosys || (!noadjfile && !systz && !predict)) {
- /* data from HW-clock are required */
- rc = synchronize_to_clock_tick();
-
- /* 2 = synchronization timeout. We don't error out if the user is
- attempting to set the RTC - the RTC could be functioning but
- contain invalid time data so we still want to allow a user to set
- the RTC time.
- */
-
- if (rc && rc != 2 && !set && !systohc)
- return EX_IOERR;
- gettimeofday(&read_time, NULL);
-
- /* If we can't synchronize to a clock tick, we likely can't read
- from the RTC so don't bother reading it again. */
- if (!rc) {
- rc = read_hardware_clock(universal, &hclock_valid, &hclocktime);
- if (rc && !set && !systohc)
- return EX_IOERR;
- }
+ /* data from HW-clock are required */
+ rc = synchronize_to_clock_tick();
+
+ /*
+ * 2 = synchronization timeout. We don't
+ * error out if the user is attempting to
+ * set the RTC - the RTC could be
+ * functioning but contain invalid time data
+ * so we still want to allow a user to set
+ * the RTC time.
+ */
+ if (rc && rc != 2 && !set && !systohc)
+ return EX_IOERR;
+ gettimeofday(&read_time, NULL);
+
+ /*
+ * If we can't synchronize to a clock tick,
+ * we likely can't read from the RTC so
+ * don't bother reading it again.
+ */
+ if (!rc) {
+ rc = read_hardware_clock(universal,
+ &hclock_valid, &hclocktime);
+ if (rc && !set && !systohc)
+ return EX_IOERR;
+ }
}
- if (show) {
- display_time(hclock_valid, hclocktime,
- time_diff(read_time, startup_time));
- } else if (set) {
- set_hardware_clock_exact(set_time, startup_time,
- universal, testing);
- if (!noadjfile)
- adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime,
- time_diff(read_time, startup_time));
- } else if (adjust) {
- do_adjustment(&adjtime, hclock_valid, hclocktime,
- read_time, universal, testing);
- } else if (systohc) {
- struct timeval nowtime, reftime;
- /* We can only set_hardware_clock_exact to a whole seconds
- time, so we set it with reference to the most recent
- whole seconds time.
- */
- gettimeofday(&nowtime, NULL);
- reftime.tv_sec = nowtime.tv_sec;
- reftime.tv_usec = 0;
-
- set_hardware_clock_exact((time_t) reftime.tv_sec, reftime,
- universal, testing);
- if (!noadjfile)
- adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid,
- hclocktime, (double) read_time.tv_usec / 1E6);
- } else if (hctosys) {
- rc = set_system_clock(hclock_valid, hclocktime, testing);
- if (rc) {
- printf(_("Unable to set system clock.\n"));
- return rc;
- }
+ if (show) {
+ display_time(hclock_valid, hclocktime,
+ time_diff(read_time, startup_time));
+ } else if (set) {
+ set_hardware_clock_exact(set_time, startup_time,
+ universal, testing);
+ if (!noadjfile)
+ adjust_drift_factor(&adjtime, set_time,
+ hclock_valid,
+ hclocktime,
+ time_diff(read_time, startup_time));
+ } else if (adjust) {
+ do_adjustment(&adjtime, hclock_valid,
+ hclocktime, read_time, universal, testing);
+ } else if (systohc) {
+ struct timeval nowtime, reftime;
+ /*
+ * We can only set_hardware_clock_exact to a
+ * whole seconds time, so we set it with
+ * reference to the most recent whole
+ * seconds time.
+ */
+ gettimeofday(&nowtime, NULL);
+ reftime.tv_sec = nowtime.tv_sec;
+ reftime.tv_usec = 0;
+ set_hardware_clock_exact((time_t)
+ reftime.tv_sec,
+ reftime, universal, testing);
+ if (!noadjfile)
+ adjust_drift_factor(&adjtime, (time_t)
+ reftime.tv_sec,
+ hclock_valid, hclocktime, (double)
+ read_time.tv_usec / 1E6);
+ } else if (hctosys) {
+ rc = set_system_clock(hclock_valid, hclocktime, testing);
+ if (rc) {
+ printf(_("Unable to set system clock.\n"));
+ return rc;
+ }
} else if (systz) {
- rc = set_system_clock_timezone(universal, testing);
- if (rc) {
- printf(_("Unable to set system clock.\n"));
- return rc;
- }
- } else if (predict) {
- int adjustment;
- double retro;
-
- calculate_adjustment(adjtime.drift_factor,
- adjtime.last_adj_time,
- adjtime.not_adjusted,
- set_time,
- &adjustment, &retro);
- if (debug) {
- printf(_("At %ld seconds after 1969, RTC is predicted to read %ld seconds after 1969.\n"),
- set_time, set_time + adjustment);
- }
- display_time(TRUE, set_time + adjustment, -retro);
- }
- if (!noadjfile)
- save_adjtime(adjtime, testing);
- }
- }
- return 0;
+ rc = set_system_clock_timezone(universal, testing);
+ if (rc) {
+ printf(_("Unable to set system clock.\n"));
+ return rc;
+ }
+ } else if (predict) {
+ int adjustment;
+ double retro;
+
+ calculate_adjustment(adjtime.drift_factor,
+ adjtime.last_adj_time,
+ adjtime.not_adjusted,
+ set_time, &adjustment, &retro);
+ if (debug) {
+ printf(_
+ ("At %ld seconds after 1969, RTC is predicted to read %ld seconds after 1969.\n"),
+ set_time, set_time + adjustment);
+ }
+ display_time(TRUE, set_time + adjustment, -retro);
+ }
+ if (!noadjfile)
+ save_adjtime(adjtime, testing);
+ return 0;
}
-
+/*
+ * Get or set the Hardware Clock epoch value in the kernel, as appropriate.
+ * <getepoch>, <setepoch>, and <epoch> are hwclock invocation options.
+ *
+ * <epoch> == -1 if the user did not specify an "epoch" option.
+ */
#ifdef __linux__
static void
manipulate_epoch(const bool getepoch, const bool setepoch,
- const int epoch_opt, const bool testing) {
-/*----------------------------------------------------------------------------
- Get or set the Hardware Clock epoch value in the kernel, as appropriate.
- <getepoch>, <setepoch>, and <epoch> are hwclock invocation options.
-
- <epoch> == -1 if the user did not specify an "epoch" option.
-
------------------------------------------------------------------------------*/
- /*
- Maintenance note: This should work on non-Alpha machines, but the
- evidence today (98.03.04) indicates that the kernel only keeps the
- epoch value on Alphas. If that is ever fixed, this function should be
- changed.
- */
-
+ const int epoch_opt, const bool testing)
+{
+ /*
+ * Maintenance note: This should work on non-Alpha machines, but the
+ * evidence today (98.03.04) indicates that the kernel only keeps
+ * the epoch value on Alphas. If that is ever fixed, this function
+ * should be changed.
+ */
#ifndef __alpha__
- fprintf(stderr, _("The kernel keeps an epoch value for the Hardware Clock "
- "only on an Alpha machine.\nThis copy of hwclock was built for "
- "a machine other than Alpha\n(and thus is presumably not running "
- "on an Alpha now). No action taken.\n"));
+ fprintf(stderr,
+ _("The kernel keeps an epoch value for the Hardware Clock "
+ "only on an Alpha machine.\nThis copy of hwclock was built for "
+ "a machine other than Alpha\n(and thus is presumably not running "
+ "on an Alpha now). No action taken.\n"));
#else
- if (getepoch) {
- unsigned long epoch;
-
- if (get_epoch_rtc(&epoch, 0))
- fprintf(stderr, _("Unable to get the epoch value from the kernel.\n"));
- else
- printf(_("Kernel is assuming an epoch value of %lu\n"), epoch);
- } else if (setepoch) {
- if (epoch_opt == -1)
- fprintf(stderr, _("To set the epoch value, you must use the 'epoch' "
- "option to tell to what value to set it.\n"));
- else if (testing)
- printf(_("Not setting the epoch to %d - testing only.\n"),
- epoch_opt);
- else if (set_epoch_rtc(epoch_opt))
- printf(_("Unable to set the epoch value in the kernel.\n"));
- }
+ if (getepoch) {
+ unsigned long epoch;
+
+ if (get_epoch_rtc(&epoch, 0))
+ fprintf(stderr,
+ _
+ ("Unable to get the epoch value from the kernel.\n"));
+ else
+ printf(_("Kernel is assuming an epoch value of %lu\n"),
+ epoch);
+ } else if (setepoch) {
+ if (epoch_opt == -1)
+ fprintf(stderr,
+ _
+ ("To set the epoch value, you must use the 'epoch' "
+ "option to tell to what value to set it.\n"));
+ else if (testing)
+ printf(_
+ ("Not setting the epoch to %d - testing only.\n"),
+ epoch_opt);
+ else if (set_epoch_rtc(epoch_opt))
+ printf(_
+ ("Unable to set the epoch value in the kernel.\n"));
+ }
#endif
}
#endif
@@ -1314,123 +1344,118 @@ manipulate_epoch(const bool getepoch, const bool setepoch,
#define RTC_DEV "/dev/rtc"
#endif
-static void
-out_version(void) {
+static void out_version(void)
+{
printf(_("%s from %s\n"), MYNAME, PACKAGE_STRING);
}
/*
- usage - Output (error and) usage information
-
- This function is called both directly from main to show usage
- information and as fatal function from shhopt if some argument is
- not understood. In case of normal usage info FMT should be NULL.
- In that case the info is printed to stdout. If FMT is given
- usage will act like fprintf( stderr, fmt, ... ), show a usage
- information and terminate the program afterwards.
-*/
-static void
-usage( const char *fmt, ... ) {
- FILE *usageto;
- va_list ap;
-
- usageto = fmt ? stderr : stdout;
-
- fprintf( usageto, _(
- "hwclock - query and set the hardware clock (RTC)\n\n"
- "Usage: hwclock [function] [options...]\n\n"
- "Functions:\n"
- " -h | --help show this help\n"
- " -r | --show read hardware clock and print result\n"
- " --set set the rtc to the time given with --date\n"
- " -s | --hctosys set the system time from the hardware clock\n"
- " -w | --systohc set the hardware clock to the current system time\n"
- " --systz set the system time based on the current timezone\n"
- " --adjust adjust the rtc to account for systematic drift since\n"
- " the clock was last set or adjusted\n"
+ * usage - Output (error and) usage information
+ *
+ * This function is called both directly from main to show usage information
+ * and as fatal function from shhopt if some argument is not understood. In
+ * case of normal usage info FMT should be NULL. In that case the info is
+ * printed to stdout. If FMT is given usage will act like fprintf( stderr,
+ * fmt, ... ), show a usage information and terminate the program
+ * afterwards.
+ */
+static void usage(const char *fmt, ...)
+{
+ FILE *usageto;
+ va_list ap;
+
+ usageto = fmt ? stderr : stdout;
+
+ fprintf(usageto,
+ _("hwclock - query and set the hardware clock (RTC)\n\n"
+ "Usage: hwclock [function] [options...]\n\n" "Functions:\n"
+ " -h | --help show this help\n"
+ " -r | --show read hardware clock and print result\n"
+ " --set set the rtc to the time given with --date\n"
+ " -s | --hctosys set the system time from the hardware clock\n"
+ " -w | --systohc set the hardware clock to the current system time\n"
+ " --systz set the system time based on the current timezone\n"
+ " --adjust adjust the rtc to account for systematic drift since\n"
+ " the clock was last set or adjusted\n"
#ifdef __linux__
- " --getepoch print out the kernel's hardware clock epoch value\n"
- " --setepoch set the kernel's hardware clock epoch value to the \n"
- " value given with --epoch\n"
+ " --getepoch print out the kernel's hardware clock epoch value\n"
+ " --setepoch set the kernel's hardware clock epoch value to the \n"
+ " value given with --epoch\n"
#endif
- " --predict predict rtc reading at time given with --date\n"
- " -v | --version print out the version of hwclock to stdout\n"
- "\nOptions: \n"
- " -u | --utc the hardware clock is kept in UTC\n"
- " --localtime the hardware clock is kept in local time\n"
+ " --predict predict rtc reading at time given with --date\n"
+ " -v | --version print out the version of hwclock to stdout\n"
+ "\nOptions: \n"
+ " -u | --utc the hardware clock is kept in UTC\n"
+ " --localtime the hardware clock is kept in local time\n"
#ifdef __linux__
- " -f | --rtc=path special /dev/... file to use instead of default\n"
+ " -f | --rtc=path special /dev/... file to use instead of default\n"
#endif
- " --directisa access the ISA bus directly instead of %s\n"
- " --badyear ignore rtc's year because the bios is broken\n"
- " --date specifies the time to which to set the hardware clock\n"
- " --epoch=year specifies the year which is the beginning of the \n"
- " hardware clock's epoch value\n"
- " --noadjfile do not access /etc/adjtime. Requires the use of\n"
- " either --utc or --localtime\n"
- " --adjfile=path specifies the path to the adjust file (default is\n"
- " /etc/adjtime)\n"
- " --test do everything except actually updating the hardware\n"
- " clock or anything else\n"
- " -D | --debug debug mode\n"
- "\n"
- ),RTC_DEV);
+ " --directisa access the ISA bus directly instead of %s\n"
+ " --badyear ignore rtc's year because the bios is broken\n"
+ " --date specifies the time to which to set the hardware clock\n"
+ " --epoch=year specifies the year which is the beginning of the \n"
+ " hardware clock's epoch value\n"
+ " --noadjfile do not access /etc/adjtime. Requires the use of\n"
+ " either --utc or --localtime\n"
+ " --adjfile=path specifies the path to the adjust file (default is\n"
+ " /etc/adjtime)\n"
+ " --test do everything except actually updating the hardware\n"
+ " clock or anything else\n"
+ " -D | --debug debug mode\n" "\n"), RTC_DEV);
#ifdef __alpha__
- fprintf(usageto, _(
- " -J|--jensen, -A|--arc, -S|--srm, -F|--funky-toy\n"
- " tell hwclock the type of alpha you have (see hwclock(8))\n"
- "\n"
- ) );
+ fprintf(usageto, _(" -J|--jensen, -A|--arc, -S|--srm, -F|--funky-toy\n"
+ " tell hwclock the type of alpha you have (see hwclock(8))\n"
+ "\n"));
#endif
- fflush(stdout);
- if (fmt) {
- usageto = stderr;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
+ fflush(stdout);
+ if (fmt) {
+ usageto = stderr;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
- hwclock_exit(fmt ? EX_USAGE : 0);
+ hwclock_exit(fmt ? EX_USAGE : 0);
}
static const struct option longopts[] = {
- { "adjust", 0, 0, 'a' },
- { "help", 0, 0, 'h' },
- { "show", 0, 0, 'r' },
- { "hctosys", 0, 0, 's' },
- { "utc", 0, 0, 'u' },
- { "version", 0, 0, 'v' },
- { "systohc", 0, 0, 'w' },
- { "debug", 0, 0, 'D' },
+ {"adjust", 0, 0, 'a'},
+ {"help", 0, 0, 'h'},
+ {"show", 0, 0, 'r'},
+ {"hctosys", 0, 0, 's'},
+ {"utc", 0, 0, 'u'},
+ {"version", 0, 0, 'v'},
+ {"systohc", 0, 0, 'w'},
+ {"debug", 0, 0, 'D'},
#ifdef __alpha__
- { "ARC", 0, 0, 'A' },
- { "arc", 0, 0, 'A' },
- { "Jensen", 0, 0, 'J' },
- { "jensen", 0, 0, 'J' },
- { "SRM", 0, 0, 'S' },
- { "srm", 0, 0, 'S' },
- { "funky-toy", 0, 0, 'F'},
+ {"ARC", 0, 0, 'A'},
+ {"arc", 0, 0, 'A'},
+ {"Jensen", 0, 0, 'J'},
+ {"jensen", 0, 0, 'J'},
+ {"SRM", 0, 0, 'S'},
+ {"srm", 0, 0, 'S'},
+ {"funky-toy", 0, 0, 'F'},
#endif
- { "set", 0, 0, 128 },
+ {"set", 0, 0, 128},
#ifdef __linux__
- { "getepoch", 0, 0, 129 },
- { "setepoch", 0, 0, 130 },
+ {"getepoch", 0, 0, 129},
+ {"setepoch", 0, 0, 130},
#endif
- { "noadjfile", 0, 0, 131 },
- { "localtime", 0, 0, 132 },
- { "badyear", 0, 0, 133 },
- { "directisa", 0, 0, 134 },
- { "test", 0, 0, 135 },
- { "date", 1, 0, 136 },
- { "epoch", 1, 0, 137 },
+ {"noadjfile", 0, 0, 131},
+ {"localtime", 0, 0, 132},
+ {"badyear", 0, 0, 133},
+ {"directisa", 0, 0, 134},
+ {"test", 0, 0, 135},
+ {"date", 1, 0, 136},
+ {"epoch", 1, 0, 137},
#ifdef __linux__
- { "rtc", 1, 0, 'f' },
+ {"rtc", 1, 0, 'f'},
#endif
- { "adjfile", 1, 0, 138 },
- { "systz", 0, 0, 139 },
- { "predict-hc", 0, 0, 140 },
- { NULL, 0, 0, 0 }
+ {"adjfile", 1, 0, 138},
+ {"systz", 0, 0, 139},
+ {"predict-hc", 0, 0, 140},
+ {NULL, 0, 0, 0}
};
/*
@@ -1442,20 +1467,22 @@ static const struct option longopts[] = {
* 0: OK (or not)
* 1: failure
*/
-int
-main(int argc, char **argv) {
-
+int main(int argc, char **argv)
+{
struct timeval startup_time;
- /* The time we started up, in seconds into the epoch, including
- fractions. */
- time_t set_time = 0; /* Time to which user said to set Hardware Clock */
+ /*
+ * The time we started up, in seconds into the epoch, including
+ * fractions.
+ */
+ time_t set_time = 0; /* Time to which user said to set Hardware Clock */
- bool permitted; /* User is permitted to do the function */
+ bool permitted; /* User is permitted to do the function */
int rc, c;
/* Variables set by various options; show may also be set later */
/* The options debug, badyear and epoch_option are global */
- bool show, set, systohc, hctosys, systz, adjust, getepoch, setepoch, predict;
+ bool show, set, systohc, hctosys, systz, adjust, getepoch, setepoch,
+ predict;
bool utc, testing, local_opt, noadjfile, directisa;
char *date_opt;
#ifdef __alpha__
@@ -1468,32 +1495,37 @@ main(int argc, char **argv) {
hwaudit_fd = audit_open();
if (hwaudit_fd < 0 && !(errno == EINVAL || errno == EPROTONOSUPPORT ||
errno == EAFNOSUPPORT)) {
- /* You get these error codes only when the kernel doesn't have
- * audit compiled in. */
+ /*
+ * You get these error codes only when the kernel doesn't
+ * have audit compiled in.
+ */
fprintf(stderr, _("%s: Unable to connect to audit system\n"),
- MYNAME);
+ MYNAME);
return EX_NOPERM;
}
#endif
setlocale(LC_ALL, "");
#ifdef LC_NUMERIC
- /* We need LC_CTYPE and LC_TIME and LC_MESSAGES, but must avoid
- LC_NUMERIC since it gives problems when we write to /etc/adjtime.
- - gqueri@mail.dotcom.fr */
+ /*
+ * We need LC_CTYPE and LC_TIME and LC_MESSAGES, but must avoid
+ * LC_NUMERIC since it gives problems when we write to /etc/adjtime.
+ * - gqueri@mail.dotcom.fr
+ */
setlocale(LC_NUMERIC, "C");
#endif
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* Set option defaults */
- show = set = systohc = hctosys = systz = adjust = noadjfile = predict = FALSE;
+ show = set = systohc = hctosys = systz = adjust = noadjfile = predict =
+ FALSE;
getepoch = setepoch = utc = local_opt = testing = debug = FALSE;
#ifdef __alpha__
ARCconsole = Jensen = SRM = funky_toy = directisa = badyear = FALSE;
#endif
date_opt = NULL;
- while ((c = getopt_long (argc, argv, "?hvVDarsuwAJSFf:", longopts, NULL))
+ while ((c = getopt_long(argc, argv, "?hvVDarsuwAJSFf:", longopts, NULL))
!= -1) {
switch (c) {
case 'D':
@@ -1543,7 +1575,7 @@ main(int argc, char **argv) {
noadjfile = TRUE;
break;
case 132:
- local_opt = TRUE; /* --localtime */
+ local_opt = TRUE; /* --localtime */
break;
case 133:
badyear = TRUE;
@@ -1552,33 +1584,33 @@ main(int argc, char **argv) {
directisa = TRUE;
break;
case 135:
- testing = TRUE; /* --test */
+ testing = TRUE; /* --test */
break;
case 136:
- date_opt = optarg; /* --date */
+ date_opt = optarg; /* --date */
break;
case 137:
epoch_option = atoi(optarg); /* --epoch */
break;
case 138:
- adj_file_name = optarg; /* --adjfile */
+ adj_file_name = optarg; /* --adjfile */
break;
case 139:
- systz = TRUE; /* --systz */
+ systz = TRUE; /* --systz */
break;
case 140:
- predict = TRUE; /* --predict-hc */
+ predict = TRUE; /* --predict-hc */
break;
#ifdef __linux__
case 'f':
- rtc_dev_name = optarg; /* --rtc */
+ rtc_dev_name = optarg; /* --rtc */
break;
#endif
- case 'v': /* --version */
+ case 'v': /* --version */
case 'V':
out_version();
return 0;
- case 'h': /* --help */
+ case 'h': /* --help */
case '?':
default:
usage(NULL);
@@ -1591,19 +1623,18 @@ main(int argc, char **argv) {
#ifdef HAVE_LIBAUDIT
if (testing != TRUE) {
if (adjust == TRUE || hctosys == TRUE || systohc == TRUE ||
- set == TRUE || setepoch == TRUE) {
+ set == TRUE || setepoch == TRUE) {
hwaudit_on = TRUE;
}
}
#endif
if (argc > 0) {
usage(_("%s takes no non-option arguments. "
- "You supplied %d.\n"),
- MYNAME, argc);
+ "You supplied %d.\n"), MYNAME, argc);
}
if (show + set + systohc + hctosys + systz + adjust + getepoch
- + setepoch + predict > 1){
+ + setepoch + predict > 1) {
fprintf(stderr, _("You have specified multiple functions.\n"
"You can only perform one function "
"at a time.\n"));
@@ -1638,7 +1669,6 @@ main(int argc, char **argv) {
"either --utc or --localtime\n"), MYNAME);
hwclock_exit(EX_USAGE);
}
-
#ifdef __alpha__
set_cmos_epoch(ARCconsole, SRM);
set_cmos_access(Jensen, funky_toy);
@@ -1656,8 +1686,7 @@ main(int argc, char **argv) {
if (!(show | set | systohc | hctosys | systz | adjust | getepoch
| setepoch | predict))
- show = 1; /* default to show */
-
+ show = 1; /* default to show */
if (getuid() == 0)
permitted = TRUE;
@@ -1710,15 +1739,15 @@ main(int argc, char **argv) {
}
rc = manipulate_clock(show, adjust, noadjfile, set, set_time,
- hctosys, systohc, systz, startup_time, utc,
- local_opt, testing, predict);
+ hctosys, systohc, systz, startup_time, utc,
+ local_opt, testing, predict);
hwclock_exit(rc);
- return rc; /* Not reached */
+ return rc; /* Not reached */
}
/* A single routine for greater uniformity */
-void
-outsyserr(char *msg, ...) {
+void outsyserr(char *msg, ...)
+{
va_list args;
int errsv = errno;
@@ -1726,144 +1755,130 @@ outsyserr(char *msg, ...) {
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
- fprintf(stderr, ", errno=%d: %s.\n",
- errsv, strerror(errsv));
+ fprintf(stderr, ", errno=%d: %s.\n", errsv, strerror(errsv));
}
-
#ifdef HAVE_LIBAUDIT
-void
-hwaudit_exit(int status)
+void hwaudit_exit(int status)
{
if (hwaudit_on) {
audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG,
- "changing system time", NULL, NULL, NULL, status ? 0 : 1);
+ "changing system time", NULL, NULL, NULL,
+ status ? 0 : 1);
close(hwaudit_fd);
}
exit(status);
}
#endif
-/****************************************************************************
-
- History of this program:
-
- 98.08.12 BJH Version 2.4
-
- Don't use century byte from Hardware Clock. Add comments telling why.
-
-
- 98.06.20 BJH Version 2.3.
-
- Make --hctosys set the kernel timezone from TZ environment variable
- and/or /usr/lib/zoneinfo. From Klaus Ripke (klaus@ripke.com).
-
- 98.03.05 BJH. Version 2.2.
-
- Add --getepoch and --setepoch.
-
- Fix some word length things so it works on Alpha.
-
- Make it work when /dev/rtc doesn't have the interrupt functions.
- In this case, busywait for the top of a second instead of blocking and
- waiting for the update complete interrupt.
-
- Fix a bunch of bugs too numerous to mention.
-
- 97.06.01: BJH. Version 2.1. Read and write the century byte (Byte
- 50) of the ISA Hardware Clock when using direct ISA I/O. Problem
- discovered by job (jei@iclnl.icl.nl).
-
- Use the rtc clock access method in preference to the KDGHWCLK method.
- Problem discovered by Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>.
-
- November 1996: Version 2.0.1. Modifications by Nicolai Langfeldt
- (janl@math.uio.no) to make it compile on linux 1.2 machines as well
- as more recent versions of the kernel. Introduced the NO_CLOCK
- access method and wrote feature test code to detect absense of rtc
- headers.
-
-
-**************************************************************************
- Maintenance notes
-
- To compile this, you must use GNU compiler optimization (-O option)
- in order to make the "extern inline" functions from asm/io.h (inb(),
- etc.) compile. If you don't optimize, which means the compiler
- will generate no inline functions, the references to these functions
- in this program will be compiled as external references. Since you
- probably won't be linking with any functions by these names, you will
- have unresolved external references when you link.
-
- The program is designed to run setuid superuser, since we need to be
- able to do direct I/O. (More to the point: we need permission to
- execute the iopl() system call). (However, if you use one of the
- methods other than direct ISA I/O to access the clock, no setuid is
- required).
-
- Here's some info on how we must deal with the time that elapses while
- this program runs: There are two major delays as we run:
-
- 1) Waiting up to 1 second for a transition of the Hardware Clock so
- we are synchronized to the Hardware Clock.
-
- 2) Running the "date" program to interpret the value of our --date
- option.
-
- Reading the /etc/adjtime file is the next biggest source of delay and
- uncertainty.
-
- The user wants to know what time it was at the moment he invoked us,
- not some arbitrary time later. And in setting the clock, he is
- giving us the time at the moment we are invoked, so if we set the
- clock some time later, we have to add some time to that.
-
- So we check the system time as soon as we start up, then run "date"
- and do file I/O if necessary, then wait to synchronize with a
- Hardware Clock edge, then check the system time again to see how
- much time we spent. We immediately read the clock then and (if
- appropriate) report that time, and additionally, the delay we measured.
-
- If we're setting the clock to a time given by the user, we wait some
- more so that the total delay is an integral number of seconds, then
- set the Hardware Clock to the time the user requested plus that
- integral number of seconds. N.B. The Hardware Clock can only be set
- in integral seconds.
-
- If we're setting the clock to the system clock value, we wait for
- the system clock to reach the top of a second, and then set the
- Hardware Clock to the system clock's value.
-
- Here's an interesting point about setting the Hardware Clock: On my
- machine, when you set it, it sets to that precise time. But one can
- imagine another clock whose update oscillator marches on a steady one
- second period, so updating the clock between any two oscillator ticks
- is the same as updating it right at the earlier tick. To avoid any
- complications that might cause, we set the clock as soon as possible
- after an oscillator tick.
-
-
- About synchronizing to the Hardware Clock when reading the time: The
- precision of the Hardware Clock counters themselves is one second.
- You can't read the counters and find out that is 12:01:02.5. But if
- you consider the location in time of the counter's ticks as part of
- its value, then its precision is as infinite as time is continuous!
- What I'm saying is this: To find out the _exact_ time in the
- hardware clock, we wait until the next clock tick (the next time the
- second counter changes) and measure how long we had to wait. We
- then read the value of the clock counters and subtract the wait time
- and we know precisely what time it was when we set out to query the
- time.
-
- hwclock uses this method, and considers the Hardware Clock to have
- infinite precision.
-
-
- Enhancements needed:
-
- - When waiting for whole second boundary in set_hardware_clock_exact,
- fail if we miss the goal by more than .1 second, as could happen if
- we get pre-empted (by the kernel dispatcher).
-
-****************************************************************************/
-
+/*
+ * History of this program:
+ *
+ * 98.08.12 BJH Version 2.4
+ *
+ * Don't use century byte from Hardware Clock. Add comments telling why.
+ *
+ * 98.06.20 BJH Version 2.3.
+ *
+ * Make --hctosys set the kernel timezone from TZ environment variable
+ * and/or /usr/lib/zoneinfo. From Klaus Ripke (klaus@ripke.com).
+ *
+ * 98.03.05 BJH. Version 2.2.
+ *
+ * Add --getepoch and --setepoch.
+ *
+ * Fix some word length things so it works on Alpha.
+ *
+ * Make it work when /dev/rtc doesn't have the interrupt functions. In this
+ * case, busywait for the top of a second instead of blocking and waiting
+ * for the update complete interrupt.
+ *
+ * Fix a bunch of bugs too numerous to mention.
+ *
+ * 97.06.01: BJH. Version 2.1. Read and write the century byte (Byte 50) of
+ * the ISA Hardware Clock when using direct ISA I/O. Problem discovered by
+ * job (jei@iclnl.icl.nl).
+ *
+ * Use the rtc clock access method in preference to the KDGHWCLK method.
+ * Problem discovered by Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>.
+ *
+ * November 1996: Version 2.0.1. Modifications by Nicolai Langfeldt
+ * (janl@math.uio.no) to make it compile on linux 1.2 machines as well as
+ * more recent versions of the kernel. Introduced the NO_CLOCK access method
+ * and wrote feature test code to detect absense of rtc headers.
+ *
+ ***************************************************************************
+ * Maintenance notes
+ *
+ * To compile this, you must use GNU compiler optimization (-O option) in
+ * order to make the "extern inline" functions from asm/io.h (inb(), etc.)
+ * compile. If you don't optimize, which means the compiler will generate no
+ * inline functions, the references to these functions in this program will
+ * be compiled as external references. Since you probably won't be linking
+ * with any functions by these names, you will have unresolved external
+ * references when you link.
+ *
+ * The program is designed to run setuid superuser, since we need to be able
+ * to do direct I/O. (More to the point: we need permission to execute the
+ * iopl() system call). (However, if you use one of the methods other than
+ * direct ISA I/O to access the clock, no setuid is required).
+ *
+ * Here's some info on how we must deal with the time that elapses while
+ * this program runs: There are two major delays as we run:
+ *
+ * 1) Waiting up to 1 second for a transition of the Hardware Clock so
+ * we are synchronized to the Hardware Clock.
+ * 2) Running the "date" program to interpret the value of our --date
+ * option.
+ *
+ * Reading the /etc/adjtime file is the next biggest source of delay and
+ * uncertainty.
+ *
+ * The user wants to know what time it was at the moment he invoked us, not
+ * some arbitrary time later. And in setting the clock, he is giving us the
+ * time at the moment we are invoked, so if we set the clock some time
+ * later, we have to add some time to that.
+ *
+ * So we check the system time as soon as we start up, then run "date" and
+ * do file I/O if necessary, then wait to synchronize with a Hardware Clock
+ * edge, then check the system time again to see how much time we spent. We
+ * immediately read the clock then and (if appropriate) report that time,
+ * and additionally, the delay we measured.
+ *
+ * If we're setting the clock to a time given by the user, we wait some more
+ * so that the total delay is an integral number of seconds, then set the
+ * Hardware Clock to the time the user requested plus that integral number
+ * of seconds. N.B. The Hardware Clock can only be set in integral seconds.
+ *
+ * If we're setting the clock to the system clock value, we wait for the
+ * system clock to reach the top of a second, and then set the Hardware
+ * Clock to the system clock's value.
+ *
+ * Here's an interesting point about setting the Hardware Clock: On my
+ * machine, when you set it, it sets to that precise time. But one can
+ * imagine another clock whose update oscillator marches on a steady one
+ * second period, so updating the clock between any two oscillator ticks is
+ * the same as updating it right at the earlier tick. To avoid any
+ * complications that might cause, we set the clock as soon as possible
+ * after an oscillator tick.
+ *
+ * About synchronizing to the Hardware Clock when reading the time: The
+ * precision of the Hardware Clock counters themselves is one second. You
+ * can't read the counters and find out that is 12:01:02.5. But if you
+ * consider the location in time of the counter's ticks as part of its
+ * value, then its precision is as infinite as time is continuous! What I'm
+ * saying is this: To find out the _exact_ time in the hardware clock, we
+ * wait until the next clock tick (the next time the second counter changes)
+ * and measure how long we had to wait. We then read the value of the clock
+ * counters and subtract the wait time and we know precisely what time it
+ * was when we set out to query the time.
+ *
+ * hwclock uses this method, and considers the Hardware Clock to have
+ * infinite precision.
+ *
+ * TODO: Enhancements needed:
+ *
+ * - When waiting for whole second boundary in set_hardware_clock_exact,
+ * fail if we miss the goal by more than .1 second, as could happen if we
+ * get pre-empted (by the kernel dispatcher).
+ */