]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/hwclock.c
libdisk: write sample output to stdout
[thirdparty/util-linux.git] / sys-utils / hwclock.c
index cec712d891f2a7d1cc56d4386d1e2ea63ce99c90..c01a868267ab90fd117e723b52ffca40c786d3a7 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <time.h>
 #include <unistd.h>
 
-#define OPTUTILS_EXIT_CODE EX_USAGE
-#define XALLOC_EXIT_CODE EX_OSERR
-
 #include "c.h"
 #include "closestream.h"
 #include "nls.h"
 #include "timeutils.h"
 #include "env.h"
 #include "xalloc.h"
+#include "path.h"
+#include "strutils.h"
 
 #ifdef HAVE_LIBAUDIT
 #include <libaudit.h>
 static int hwaudit_fd = -1;
 #endif
 
+UL_DEBUG_DEFINE_MASK(hwclock);
+UL_DEBUG_DEFINE_MASKNAMES(hwclock) = UL_DEBUG_EMPTY_MASKNAMES;
+
 /* The struct that holds our hardware access routines */
 static struct clock_ops *ur;
 
@@ -105,7 +106,7 @@ struct adjtime {
         * structure is not what's in the disk file (because it has been
         * updated since read from the disk file).
         */
-       bool dirty;
+       int dirty;
        /* line 1 */
        double drift_factor;
        time_t last_adj_time;
@@ -124,6 +125,23 @@ struct adjtime {
         */
 };
 
+static void hwclock_init_debug(const char *str)
+{
+       __UL_INIT_DEBUG_FROM_STRING(hwclock, HWCLOCK_DEBUG_, 0, str);
+
+       DBG(INIT, ul_debug("hwclock debug mask: 0x%04x", hwclock_debug_mask));
+       DBG(INIT, ul_debug("hwclock version: %s", PACKAGE_STRING));
+}
+
+/* FOR TESTING ONLY: inject random delays of up to 1000ms */
+static void up_to_1000ms_sleep(void)
+{
+       int usec = random() % 1000000;
+
+       DBG(RANDOM_SLEEP, ul_debug("sleeping ~%d usec", usec));
+       xusleep(usec);
+}
+
 /*
  * time_t to timeval conversion.
  */
@@ -170,20 +188,20 @@ static struct timeval time_inc(struct timeval addend, double increment)
        return newtime;
 }
 
-static bool
+static int
 hw_clock_is_utc(const struct hwclock_control *ctl,
                const struct adjtime adjtime)
 {
-       bool ret;
+       int ret;
 
        if (ctl->utc)
-               ret = TRUE;     /* --utc explicitly given on command line */
+               ret = 1;        /* --utc explicitly given on command line */
        else if (ctl->local_opt)
-               ret = FALSE;    /* --localtime explicitly given */
+               ret = 0;        /* --localtime explicitly given */
        else
                /* get info from adjtime file - default is UTC */
                ret = (adjtime.local_utc != LOCAL);
-       if (ctl->debug)
+       if (ctl->verbose)
                printf(_("Assuming hardware clock is kept in %s time.\n"),
                       ret ? _("UTC") : _("local"));
        return ret;
@@ -192,11 +210,8 @@ hw_clock_is_utc(const struct hwclock_control *ctl,
 /*
  * 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.
+ * Return them as the adjtime structure <*adjtime_p>. Its defaults are
+ * initialized in main().
  */
 static int read_adjtime(const struct hwclock_control *ctl,
                        struct adjtime *adjtime_p)
@@ -207,12 +222,12 @@ static int read_adjtime(const struct hwclock_control *ctl,
        char line3[81];         /* String: third line of adjtime file */
 
        if (access(ctl->adj_file_name, R_OK) != 0)
-               return 0;
+               return EXIT_SUCCESS;
 
        adjfile = fopen(ctl->adj_file_name, "r");       /* open file for reading */
        if (adjfile == NULL) {
                warn(_("cannot open %s"), ctl->adj_file_name);
-               return EX_OSFILE;
+               return EXIT_FAILURE;
        }
 
        if (!fgets(line1, sizeof(line1), adjfile))
@@ -243,7 +258,7 @@ static int read_adjtime(const struct hwclock_control *ctl,
                }
        }
 
-       if (ctl->debug) {
+       if (ctl->verbose) {
                printf(_
                       ("Last drift adjustment done at %ld seconds after 1969\n"),
                       (long)adjtime_p->last_adj_time);
@@ -255,7 +270,7 @@ static int read_adjtime(const struct hwclock_control *ctl,
                                               UTC) ? _("UTC") : _("unknown"));
        }
 
-       return 0;
+       return EXIT_SUCCESS;
 }
 
 /*
@@ -275,12 +290,12 @@ static int synchronize_to_clock_tick(const struct hwclock_control *ctl)
 {
        int rc;
 
-       if (ctl->debug)
+       if (ctl->verbose)
                printf(_("Waiting for clock tick...\n"));
 
        rc = ur->synchronize_to_clock_tick(ctl);
 
-       if (ctl->debug) {
+       if (ctl->verbose) {
                if (rc)
                        printf(_("...synchronization failed\n"));
                else
@@ -306,10 +321,12 @@ static int synchronize_to_clock_tick(const struct hwclock_control *ctl)
  * case, we return the same fictional value mktime() does as *systime_p and
  * return *valid_p == true.
  */
-static void
+static int
 mktime_tz(const struct hwclock_control *ctl, struct tm tm,
-         bool *valid_p, time_t *systime_p)
+         time_t *systime_p)
 {
+       int valid;
+
        if (ctl->universal)
                *systime_p = timegm(&tm);
        else
@@ -321,21 +338,22 @@ mktime_tz(const struct hwclock_control *ctl, struct tm tm,
                 * (however, not containing valid values does _not_ imply
                 * mktime() returns -1).
                 */
-               *valid_p = FALSE;
-               if (ctl->debug)
+               valid = 0;
+               if (ctl->verbose)
                        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;
-               if (ctl->debug)
+               valid = 1;
+               if (ctl->verbose)
                        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);
        }
+       return valid;
 }
 
 /*
@@ -346,7 +364,7 @@ mktime_tz(const struct hwclock_control *ctl, struct tm tm,
  */
 static int
 read_hardware_clock(const struct hwclock_control *ctl,
-                   bool * valid_p, time_t *systime_p)
+                   int *valid_p, time_t *systime_p)
 {
        struct tm tm;
        int err;
@@ -355,12 +373,12 @@ read_hardware_clock(const struct hwclock_control *ctl,
        if (err)
                return err;
 
-       if (ctl->debug)
+       if (ctl->verbose)
                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(ctl, tm, valid_p, systime_p);
+       *valid_p = mktime_tz(ctl, tm, systime_p);
 
        return 0;
 }
@@ -379,22 +397,61 @@ set_hardware_clock(const struct hwclock_control *ctl, const time_t newtime)
         */
 
        if (ctl->universal)
-               new_broken_time = *gmtime(&newtime);
+               gmtime_r(&newtime, &new_broken_time);
        else
-               new_broken_time = *localtime(&newtime);
+               localtime_r(&newtime, &new_broken_time);
 
-       if (ctl->debug)
+       if (ctl->verbose)
                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 (ctl->testing)
-               printf(_("Test mode: clock was not changed\n"));
-       else
+       if (!ctl->testing)
                ur->set_hardware_clock(ctl, &new_broken_time);
 }
 
+static double
+get_hardware_delay(const struct hwclock_control *ctl)
+{
+       const char *devpath, *rtcname;
+       char name[128 + 1];
+       struct path_cxt *pc;
+       int rc;
+
+       devpath = ur->get_device_path();
+       if (!devpath)
+               goto unknown;
+
+       rtcname = strrchr(devpath, '/');
+       if (!rtcname || !*(rtcname + 1))
+               goto unknown;
+       rtcname++;
+
+       pc = ul_new_path("/sys/class/rtc/%s", rtcname);
+       if (!pc)
+               goto unknown;
+       rc = ul_path_scanf(pc, "name", "%128[^\n ]", &name);
+       ul_unref_path(pc);
+
+       if (rc != 1 || !*name)
+               goto unknown;
+
+       if (ctl->verbose)
+               printf(_("RTC type: '%s'\n"), name);
+
+       /* MC146818A-compatible (x86) */
+       if (strcmp(name, "rtc_cmos") == 0)
+               return 0.5;
+
+       /* Another HW */
+       return 0;
+unknown:
+       /* Let's be backwardly compatible */
+       return 0.5;
+}
+
+
 /*
  * Set the Hardware Clock to the time "sethwtime", in local time zone or
  * UTC, according to "universal".
@@ -404,7 +461,8 @@ set_hardware_clock(const struct hwclock_control *ctl, const time_t newtime)
  * example, if "sethwtime" is 14:03:05 and "refsystime" is 12:10:04.5 and
  * the current system time is 12:10:06.0: Wait .5 seconds (to make exactly 2
  * seconds since "refsystime") and then set the Hardware Clock to 14:03:07,
- * thus getting a precise and retroactive setting of the clock.
+ * thus getting a precise and retroactive setting of the clock. The .5 delay is
+ * default on x86, see --delay and get_hardware_delay().
  *
  * (Don't be confused by the fact that the system clock and the Hardware
  * Clock differ by two hours in the above example. That's just to remind you
@@ -466,25 +524,31 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
        time_t newhwtime = sethwtime;
        double target_time_tolerance_secs = 0.001;  /* initial value */
        double tolerance_incr_secs = 0.001;         /* initial value */
-       const double RTC_SET_DELAY_SECS = 0.5;      /* 500 ms */
-       const struct timeval RTC_SET_DELAY_TV = { 0, RTC_SET_DELAY_SECS * 1E6 };
+       double delay;
+       struct timeval rtc_set_delay_tv;
 
        struct timeval targetsystime;
        struct timeval nowsystime;
        struct timeval prevsystime = refsystime;
        double deltavstarget;
 
-       timeradd(&refsystime, &RTC_SET_DELAY_TV, &targetsystime);
+       if (ctl->rtc_delay != -1.0)        /* --delay specified */
+               delay = ctl->rtc_delay;
+       else
+               delay = get_hardware_delay(ctl);
+
+       if (ctl->verbose)
+               printf(_("Using delay: %.6f seconds\n"), delay);
+
+       rtc_set_delay_tv.tv_sec = 0;
+       rtc_set_delay_tv.tv_usec = delay * 1E6;
+
+       timeradd(&refsystime, &rtc_set_delay_tv, &targetsystime);
 
        while (1) {
                double ticksize;
 
-               /* FOR TESTING ONLY: inject random delays of up to 1000ms */
-               if (ctl->debug >= 10) {
-                       int usec = random() % 1000000;
-                       printf(_("sleeping ~%d usec\n"), usec);
-                       xusleep(usec);
-               }
+               ON_DBG(RANDOM_SLEEP, up_to_1000ms_sleep());
 
                gettimeofday(&nowsystime, NULL);
                deltavstarget = time_diff(nowsystime, targetsystime);
@@ -492,7 +556,7 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
                prevsystime = nowsystime;
 
                if (ticksize < 0) {
-                       if (ctl->debug)
+                       if (ctl->verbose)
                                printf(_("time jumped backward %.6f seconds "
                                         "to %ld.%06ld - retargeting\n"),
                                       ticksize, nowsystime.tv_sec,
@@ -500,13 +564,11 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
                        /* The retarget is handled at the end of the loop. */
                } else if (deltavstarget < 0) {
                        /* deltavstarget < 0 if current time < target time */
-                       if (ctl->debug >= 2)
-                               printf(_("%ld.%06ld < %ld.%06ld (%.6f)\n"),
-                                      nowsystime.tv_sec,
-                                      nowsystime.tv_usec,
-                                      targetsystime.tv_sec,
-                                      targetsystime.tv_usec,
-                                      deltavstarget);
+                       DBG(DELTA_VS_TARGET,
+                           ul_debug("%ld.%06ld < %ld.%06ld (%.6f)",
+                                    nowsystime.tv_sec, nowsystime.tv_usec,
+                                    targetsystime.tv_sec,
+                                    targetsystime.tv_usec, deltavstarget));
                        continue;  /* not there yet - keep spinning */
                } else if (deltavstarget <= target_time_tolerance_secs) {
                        /* Close enough to the target time; done waiting. */
@@ -516,7 +578,7 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
                         * We missed our window.  Increase the tolerance and
                         * aim for the next opportunity.
                         */
-                       if (ctl->debug)
+                       if (ctl->verbose)
                                printf(_("missed it - %ld.%06ld is too far "
                                         "past %ld.%06ld (%.6f > %.6f)\n"),
                                       nowsystime.tv_sec,
@@ -542,9 +604,9 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
 
        newhwtime = sethwtime
                    + (int)(time_diff(nowsystime, refsystime)
-                           - RTC_SET_DELAY_SECS /* don't count this */
+                           - delay /* don't count this */
                            + 0.5 /* for rounding */);
-       if (ctl->debug)
+       if (ctl->verbose)
                printf(_("%ld.%06ld is close enough to %ld.%06ld (%.6f < %.6f)\n"
                         "Set RTC to %ld (%ld + %d; refsystime = %ld.%06ld)\n"),
                       nowsystime.tv_sec, nowsystime.tv_usec,
@@ -557,193 +619,99 @@ set_hardware_clock_exact(const struct hwclock_control *ctl,
        set_hardware_clock(ctl, newhwtime);
 }
 
-/*
- * Put the time "hwctime" on standard output in display format. Except if
- * hclock_valid == false, just tell standard output that we don't know what
- * time it is.
- */
-static void
-display_time(const bool hclock_valid, struct timeval hwctime)
-{
-       if (!hclock_valid)
-               warnx(_
-                     ("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)."));
-       else {
-               char buf[ISO_8601_BUFSIZ];
-
-               strtimeval_iso(&hwctime, ISO_8601_DATE|ISO_8601_TIME|ISO_8601_DOTUSEC|
-                                        ISO_8601_TIMEZONE|ISO_8601_SPACE,
-                                        buf, sizeof(buf));
-               printf("%s\n", buf);
-       }
-}
-
-/*
- * 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.
- *
- * If this is the first call of settimeofday since boot, then this also sets
- * the kernel variable persistent_clock_is_local so that NTP 11 minute mode
- * will update the Hardware Clock with the proper timescale. If the Hardware
- * Clock's timescale configuration is changed then a reboot is required for
- * persistent_clock_is_local to be updated.
- *
- * 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 struct hwclock_control *ctl, const bool hclock_valid,
-                const struct timeval newtime)
+display_time(struct timeval hwctime)
 {
-       int retcode;
+       char buf[ISO_BUFSIZ];
 
-       if (!hclock_valid) {
-               warnx(_
-                     ("The Hardware Clock does not contain a valid time, so "
-                      "we cannot set the System Time from it."));
-               retcode = 1;
-       } else {
-               const struct timeval *tv_null = NULL;
-               struct tm *broken;
-               int minuteswest;
-               int rc = 0;
-
-               broken = localtime(&newtime.tv_sec);
-#ifdef HAVE_TM_GMTOFF
-               minuteswest = -broken->tm_gmtoff / 60;  /* GNU extension */
-#else
-               minuteswest = timezone / 60;
-               if (broken->tm_isdst)
-                       minuteswest -= 60;
-#endif
+       if (strtimeval_iso(&hwctime, ISO_TIMESTAMP_DOT, buf, sizeof(buf)))
+               return EXIT_FAILURE;
 
-               if (ctl->debug) {
-                       printf(_("Calling settimeofday:\n"));
-                       printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"),
-                              newtime.tv_sec, newtime.tv_usec);
-                       printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest);
-               }
-               if (ctl->testing) {
-                       printf(_
-                              ("Test mode: clock was not changed\n"));
-                       retcode = 0;
-               } else {
-                       const struct timezone tz = { minuteswest, 0 };
-
-                       /* Set kernel persistent_clock_is_local so that 11 minute
-                        * mode does not clobber the Hardware Clock with UTC. This
-                        * is only available on first call of settimeofday after boot.
-                        */
-                       if (!ctl->universal)
-                               rc = settimeofday(tv_null, &tz);
-                       if (!rc)
-                               rc = settimeofday(&newtime, &tz);
-                       if (rc) {
-                               warn(_("settimeofday() failed"));
-                               retcode = 1;
-                       } else
-                               retcode = 0;
-               }
-       }
-       return retcode;
+       printf("%s\n", buf);
+       return EXIT_SUCCESS;
 }
 
 /*
- * 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.
+ * Adjusts System time, sets the kernel's timezone and RTC timescale.
+ *
+ * The kernel warp_clock function adjusts the System time according to the
+ * tz.tz_minuteswest argument and sets PCIL (see below). At boot settimeofday(2)
+ * has one-shot access to this function as shown in the table below.
+ *
+ * +-------------------------------------------------------------------+
+ * |                       settimeofday(tv, tz)                        |
+ * |-------------------------------------------------------------------|
+ * |     Arguments     |  System Time  | PCIL |           | warp_clock |
+ * |   tv    |   tz    | set  | warped | set  | firsttime |   locked   |
+ * |---------|---------|---------------|------|-----------|------------|
+ * | pointer | NULL    |  yes |   no   |  no  |     1     |    no      |
+ * | pointer | pointer |  yes |   no   |  no  |     0     |    yes     |
+ * | NULL    | ptr2utc |  no  |   no   |  no  |     0     |    yes     |
+ * | NULL    | pointer |  no  |   yes  |  yes |     0     |    yes     |
+ * +-------------------------------------------------------------------+
+ * ptr2utc: tz.tz_minuteswest is zero (UTC).
+ * PCIL: persistent_clock_is_local, sets the "11 minute mode" timescale.
+ * firsttime: locks the warp_clock function (initialized to 1 at boot).
+ *
+ * +---------------------------------------------------------------------------+
+ * |  op     | RTC scale | settimeofday calls                                  |
+ * |---------|-----------|-----------------------------------------------------|
+ * | systz   |   Local   | 1) warps system time*, sets PCIL* and kernel tz     |
+ * | systz   |   UTC     | 1st) locks warp_clock* 2nd) sets kernel tz          |
+ * | hctosys |   Local   | 1st) sets PCIL* 2nd) sets system time and kernel tz |
+ * | hctosys |   UTC     | 1) sets system time and kernel tz                   |
+ * +---------------------------------------------------------------------------+
+ *                         * only on first call after boot
  */
-static int set_system_clock_timezone(const struct hwclock_control *ctl)
+static int
+set_system_clock(const struct hwclock_control *ctl,
+                const struct timeval newtime)
 {
-       int retcode;
-       struct timeval tv;
-       struct tm *broken;
+       struct tm broken;
        int minuteswest;
-
-       gettimeofday(&tv, NULL);
-       if (ctl->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"), tv.tv_sec,
-                      ctime_now);
+       int rc = 0;
+       const struct timezone tz_utc = { 0 };
+
+       localtime_r(&newtime.tv_sec, &broken);
+       minuteswest = -get_gmtoff(&broken) / 60;
+
+       if (ctl->verbose) {
+               if (ctl->hctosys && !ctl->universal)
+                       printf(_("Calling settimeofday(NULL, %d) to set "
+                                "persistent_clock_is_local.\n"), minuteswest);
+               if (ctl->systz && ctl->universal)
+                       puts(_("Calling settimeofday(NULL, 0) "
+                               "to lock the warp function."));
+               if (ctl->hctosys)
+                       printf(_("Calling settimeofday(%ld.%06ld, %d)\n"),
+                              newtime.tv_sec, newtime.tv_usec, minuteswest);
+               else {
+                       printf(_("Calling settimeofday(NULL, %d) "), minuteswest);
+                       if (ctl->universal)
+                                puts(_("to set the kernel timezone."));
+                       else
+                                puts(_("to warp System time."));
+               }
        }
 
-       broken = localtime(&tv.tv_sec);
-#ifdef HAVE_TM_GMTOFF
-       minuteswest = -broken->tm_gmtoff / 60;  /* GNU extension */
-#else
-       minuteswest = timezone / 60;
-       if (broken->tm_isdst)
-               minuteswest -= 60;
-#endif
-
-       if (ctl->debug) {
-               struct tm broken_time;
-               char ctime_now[200];
-
-               gettimeofday(&tv, NULL);
-               if (!ctl->universal)
-                       tv.tv_sec += minuteswest * 60;
+       if (!ctl->testing) {
+               const struct timezone tz = { minuteswest };
 
-               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"),
-                      tv.tv_sec, tv.tv_usec);
-               printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest);
-       }
-       if (ctl->testing) {
-               printf(_
-                      ("Test mode: clock was not changed\n"));
-               retcode = 0;
-       } else {
-               const struct timezone tz_utc = { 0, 0 };
-               const struct timezone tz = { minuteswest, 0 };
-               const struct timeval *tv_null = NULL;
-               int rc = 0;
-
-               /* The first call to settimeofday after boot will assume the systemtime
-                * is in localtime, and adjust it according to the given timezone to
-                * compensate. If the systemtime is in fact in UTC, then this is wrong
-                * so we first do a dummy call to make sure the time is not shifted.
-                */
-               if (ctl->universal)
-                       rc = settimeofday(tv_null, &tz_utc);
-
-               /* Now we set the real timezone. Due to the above dummy call, this will
-                * only warp the systemtime if the RTC is not in UTC. */
-               if (!rc)
-                       rc = settimeofday(tv_null, &tz);
+               if (ctl->hctosys && !ctl->universal)    /* set PCIL */
+                       rc = settimeofday(NULL, &tz);
+               if (ctl->systz && ctl->universal)       /* lock warp_clock */
+                       rc = settimeofday(NULL, &tz_utc);
+               if (!rc && ctl->hctosys)
+                       rc = settimeofday(&newtime, &tz);
+               else if (!rc)
+                       rc = settimeofday(NULL, &tz);
 
                if (rc) {
                        warn(_("settimeofday() failed"));
-                       retcode = 1;
-               } else
-                       retcode = 0;
+                       return  EXIT_FAILURE;
+               }
        }
-       return retcode;
+       return EXIT_SUCCESS;
 }
 
 /*
@@ -754,35 +722,25 @@ static int set_system_clock_timezone(const struct hwclock_control *ctl)
  * Update the drift factor in <*adjtime_p> based on the fact that the
  * Hardware Clock was just calibrated to <nowtime> and before that was
  * set to the <hclocktime> time scale.
- *
- * 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(const struct hwclock_control *ctl,
                    struct adjtime *adjtime_p,
                    const struct timeval nowtime,
-                   const bool hclock_valid,
                    const struct timeval hclocktime)
 {
        if (!ctl->update) {
-               if (ctl->debug)
+               if (ctl->verbose)
                        printf(_("Not adjusting drift factor because the "
                                 "--update-drift option was not used.\n"));
-       } else if (!hclock_valid) {
-               if (ctl->debug)
-                       printf(_("Not adjusting drift factor because the "
-                                "Hardware Clock previously contained "
-                                "garbage.\n"));
        } else if (adjtime_p->last_calib_time == 0) {
-               if (ctl->debug)
+               if (ctl->verbose)
                        printf(_("Not adjusting drift factor because last "
                                 "calibration time is zero,\n"
                                 "so history is bad and calibration startover "
                                 "is necessary.\n"));
        } else if ((hclocktime.tv_sec - adjtime_p->last_calib_time) < 4 * 60 * 60) {
-               if (ctl->debug)
+               if (ctl->verbose)
                        printf(_("Not adjusting drift factor because it has "
                                 "been less than four hours since the last "
                                 "calibration.\n"));
@@ -820,14 +778,14 @@ adjust_drift_factor(const struct hwclock_control *ctl,
 
                drift_factor = adjtime_p->drift_factor + factor_adjust;
                if (fabs(drift_factor) > MAX_DRIFT) {
-                       if (ctl->debug)
+                       if (ctl->verbose)
                                printf(_("Clock drift factor was calculated as "
                                         "%f seconds/day.\n"
                                         "It is far too much. Resetting to zero.\n"),
                                       drift_factor);
                        drift_factor = 0;
                } else {
-                       if (ctl->debug)
+                       if (ctl->verbose)
                                printf(_("Clock drifted %f seconds in the past "
                                         "%f seconds\nin spite of a drift factor of "
                                         "%f seconds/day.\n"
@@ -845,7 +803,7 @@ adjust_drift_factor(const struct hwclock_control *ctl,
 
        adjtime_p->not_adjusted = 0;
 
-       adjtime_p->dirty = TRUE;
+       adjtime_p->dirty = 1;
 }
 
 /*
@@ -871,7 +829,7 @@ calculate_adjustment(const struct hwclock_control *ctl,
        tdrift_p->tv_sec = (time_t) floor(exact_adjustment);
        tdrift_p->tv_usec = (exact_adjustment -
                                 (double)tdrift_p->tv_sec) * 1E6;
-       if (ctl->debug) {
+       if (ctl->verbose) {
                printf(P_("Time since last adjustment is %ld second\n",
                        "Time since last adjustment is %ld seconds\n",
                       (systime - last_time)),
@@ -887,15 +845,11 @@ calculate_adjustment(const struct hwclock_control *ctl,
  * But if the contents are clean (unchanged since read from disk), don't
  * bother.
  */
-static void save_adjtime(const struct hwclock_control *ctl,
+static int save_adjtime(const struct hwclock_control *ctl,
                         const struct adjtime *adjtime)
 {
        char *content;          /* Stuff to write to disk file */
        FILE *fp;
-       int err = 0;
-
-       if (!adjtime->dirty)
-               return;
 
        xasprintf(&content, "%f %ld %f\n%ld\n%s\n",
                  adjtime->drift_factor,
@@ -904,28 +858,22 @@ static void save_adjtime(const struct hwclock_control *ctl,
                  adjtime->last_calib_time,
                  (adjtime->local_utc == LOCAL) ? "LOCAL" : "UTC");
 
-       if (ctl->testing) {
-               if (ctl->debug){
-                       printf(_("Test mode: %s was not updated with:\n%s"),
-                              ctl->adj_file_name, content);
-               }
-               free(content);
-               return;
+       if (ctl->verbose){
+               printf(_("New %s data:\n%s"),
+                      ctl->adj_file_name, content);
        }
 
-       fp = fopen(ctl->adj_file_name, "w");
-       if (fp == NULL) {
-               warn(_("Could not open file with the clock adjustment parameters "
-                      "in it (%s) for writing"), ctl->adj_file_name);
-               err = 1;
-       } else if (fputs(content, fp) < 0 || close_stream(fp) != 0) {
-               warn(_("Could not update file with the clock adjustment "
-                      "parameters (%s) in it"), ctl->adj_file_name);
-               err = 1;
+       if (!ctl->testing) {
+               fp = fopen(ctl->adj_file_name, "w");
+               if (fp == NULL) {
+                       warn(_("cannot open %s"), ctl->adj_file_name);
+                       return EXIT_FAILURE;
+               } else if (fputs(content, fp) < 0 || close_stream(fp) != 0) {
+                       warn(_("cannot update %s"), ctl->adj_file_name);
+                       return EXIT_FAILURE;
+               }
        }
-       free(content);
-       if (err)
-               warnx(_("Drift adjustment parameters not updated."));
+       return EXIT_SUCCESS;
 }
 
 /*
@@ -936,8 +884,6 @@ static void save_adjtime(const struct hwclock_control *ctl,
  * Do not update anything if the Hardware Clock does not currently present a
  * valid time.
  *
- * <hclock_valid> means the Hardware Clock contains a valid time.
- *
  * <hclocktime> is the drift corrected time read from the Hardware Clock.
  *
  * <read_time> was the system time when the <hclocktime> was read, which due
@@ -954,22 +900,15 @@ static void save_adjtime(const struct hwclock_control *ctl,
  */
 static void
 do_adjustment(const struct hwclock_control *ctl, struct adjtime *adjtime_p,
-             const bool hclock_valid, const struct timeval hclocktime,
+             const struct timeval hclocktime,
              const struct timeval read_time)
 {
-       if (!hclock_valid) {
-               warnx(_("The Hardware Clock does not contain a valid time, "
-                       "so we cannot adjust it."));
-               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 (ctl->debug)
+       if (adjtime_p->last_adj_time == 0) {
+               if (ctl->verbose)
                        printf(_("Not setting clock because last adjustment time is zero, "
                                 "so history is bad.\n"));
        } else if (fabs(adjtime_p->drift_factor) > MAX_DRIFT) {
-               if (ctl->debug)
+               if (ctl->verbose)
                        printf(_("Not setting clock because drift factor %f is far too high.\n"),
                                adjtime_p->drift_factor);
        } else {
@@ -978,7 +917,7 @@ do_adjustment(const struct hwclock_control *ctl, struct adjtime *adjtime_p,
                                                  -(hclocktime.tv_usec / 1E6)));
                adjtime_p->last_adj_time = hclocktime.tv_sec;
                adjtime_p->not_adjusted = 0;
-               adjtime_p->dirty = TRUE;
+               adjtime_p->dirty = 1;
        }
 }
 
@@ -986,126 +925,132 @@ static void determine_clock_access_method(const struct hwclock_control *ctl)
 {
        ur = NULL;
 
+#ifdef USE_HWCLOCK_CMOS
        if (ctl->directisa)
                ur = probe_for_cmos_clock();
+#endif
 #ifdef __linux__
        if (!ur)
                ur = probe_for_rtc_clock(ctl);
 #endif
        if (ur) {
-               if (ctl->debug)
+               if (ctl->verbose)
                        puts(ur->interface_name);
 
        } else {
-               if (ctl->debug)
+               if (ctl->verbose)
                        printf(_("No usable clock interface found.\n"));
                warnx(_("Cannot access the Hardware Clock via "
                        "any known method."));
-               if (!ctl->debug)
-                       warnx(_("Use the --debug option to see the "
+               if (!ctl->verbose)
+                       warnx(_("Use the --verbose option to see the "
                                "details of our search for an access "
                                "method."));
-               hwclock_exit(ctl, EX_SOFTWARE);
+               hwclock_exit(ctl, EXIT_FAILURE);
        }
 }
 
-/*
- * 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.
- */
+/* Do all the normal work of hwclock - read, set clock, etc. */
 static int
 manipulate_clock(const struct hwclock_control *ctl, const time_t set_time,
                 const struct timeval startup_time, struct adjtime *adjtime)
 {
        /* The time at which we read the Hardware Clock */
-       struct timeval read_time;
+       struct timeval read_time = { 0 };
        /*
         * The Hardware Clock gives us a valid time, or at
         * least something close enough to fool mktime().
         */
-       bool hclock_valid = FALSE;
+       int hclock_valid = 0;
        /*
         * Tick synchronized time read from the Hardware Clock and
-        * then drift correct for all operations except --show.
+        * then drift corrected for all operations except --show.
+        */
+       struct timeval hclocktime = { 0 };
+       /*
+        * hclocktime correlated to startup_time. That is, what drift
+        * corrected Hardware Clock time would have been at start up.
         */
-       struct timeval hclocktime = { 0, 0 };
+       struct timeval startup_hclocktime = { 0 };
        /* Total Hardware Clock drift correction needed. */
-       struct timeval tdrift;
-       /* local return code */
-       int rc = 0;
-
-       if (!ctl->systz && !ctl->predict && ur->get_permissions())
-               return EX_NOPERM;
+       struct timeval tdrift = { 0 };
 
        if ((ctl->set || ctl->systohc || ctl->adjust) &&
            (adjtime->local_utc == UTC) != ctl->universal) {
                adjtime->local_utc = ctl->universal ? UTC : LOCAL;
-               adjtime->dirty = TRUE;
+               adjtime->dirty = 1;
+       }
+       /*
+        * Negate the drift correction, because we want to 'predict' a
+        * Hardware Clock time that includes drift.
+        */
+       if (ctl->predict) {
+               hclocktime = t2tv(set_time);
+               calculate_adjustment(ctl, adjtime->drift_factor,
+                                    adjtime->last_adj_time,
+                                    adjtime->not_adjusted,
+                                    hclocktime.tv_sec, &tdrift);
+               hclocktime = time_inc(hclocktime, (double)
+                                     -(tdrift.tv_sec + tdrift.tv_usec / 1E6));
+               if (ctl->verbose) {
+                       printf(_ ("Target date:   %ld\n"), set_time);
+                       printf(_ ("Predicted RTC: %ld\n"), hclocktime.tv_sec);
+               }
+               return display_time(hclocktime);
        }
 
        if (ctl->systz)
-               return set_system_clock_timezone(ctl);
+               return set_system_clock(ctl, startup_time);
 
-       if (ctl->show || ctl->get || ctl->adjust || ctl->hctosys
-           || (!ctl->noadjfile && !ctl->predict)) {
-               /* data from HW-clock are required */
-               rc = synchronize_to_clock_tick(ctl);
+       if (ur->get_permissions())
+               return EXIT_FAILURE;
 
+       /*
+        * Read and drift correct RTC time; except for RTC set functions
+        * without the --update-drift option because: 1) it's not needed;
+        * 2) it enables setting a corrupted RTC without reading it first;
+        * 3) it significantly reduces system shutdown time.
+        */
+       if ( ! ((ctl->set || ctl->systohc) && !ctl->update)) {
                /*
-                * We don't error out if the user is attempting to set the
-                * RTC and synchronization timeout happens - the RTC could
-                * be functioning but contain invalid time data so we still
-                * want to allow a user to set the RTC time.
+                * Timing critical - do not change the order of, or put
+                * anything between the follow three statements.
+                * Synchronization failure MUST exit, because all drift
+                * operations are invalid without it.
                 */
-               if (rc == RTC_BUSYWAIT_FAILED && !ctl->set && !ctl->systohc)
-                       return EX_IOERR;
+               if (synchronize_to_clock_tick(ctl))
+                       return EXIT_FAILURE;
+               read_hardware_clock(ctl, &hclock_valid, &hclocktime.tv_sec);
                gettimeofday(&read_time, NULL);
 
+               if (!hclock_valid) {
+                       warnx(_("RTC read returned an invalid value."));
+                       return EXIT_FAILURE;
+               }
                /*
-                * If we can't synchronize to a clock tick,
-                * we likely can't read from the RTC so
-                * don't bother reading it again.
+                * Calculate and apply drift correction to the Hardware Clock
+                * time for everything except --show
                 */
-               if (!rc) {
-                       rc = read_hardware_clock(ctl, &hclock_valid,
-                                                &hclocktime.tv_sec);
-                       if (rc && !ctl->set && !ctl->systohc)
-                               return EX_IOERR;
-               }
+               calculate_adjustment(ctl, adjtime->drift_factor,
+                                    adjtime->last_adj_time,
+                                    adjtime->not_adjusted,
+                                    hclocktime.tv_sec, &tdrift);
+               if (!ctl->show)
+                       hclocktime = time_inc(tdrift, hclocktime.tv_sec);
+
+               startup_hclocktime =
+                time_inc(hclocktime, time_diff(startup_time, read_time));
        }
-       /*
-        * Calculate Hardware Clock drift for --predict with the user
-        * supplied --date option time, and with the time read from the
-        * Hardware Clock for all other operations.  Apply drift correction
-        * to the Hardware Clock time for everything except --show and
-        * --predict.  For --predict negate the drift correction, because we
-        * want to 'predict' a future Hardware Clock time that includes drift.
-        */
-       hclocktime = ctl->predict ? t2tv(set_time) : hclocktime;
-       calculate_adjustment(ctl, adjtime->drift_factor,
-                            adjtime->last_adj_time,
-                            adjtime->not_adjusted,
-                            hclocktime.tv_sec, &tdrift);
-       if (!ctl->show && !ctl->predict)
-               hclocktime = time_inc(tdrift, hclocktime.tv_sec);
        if (ctl->show || ctl->get) {
-               display_time(hclock_valid,
-                            time_inc(hclocktime, -time_diff
-                                     (read_time, startup_time)));
+               return display_time(startup_hclocktime);
        } else if (ctl->set) {
                set_hardware_clock_exact(ctl, set_time, startup_time);
                if (!ctl->noadjfile)
-                       adjust_drift_factor(ctl, adjtime,
-                                           time_inc(t2tv(set_time), time_diff
-                                                    (read_time, startup_time)),
-                                           hclock_valid, hclocktime);
+                       adjust_drift_factor(ctl, adjtime, t2tv(set_time),
+                                           startup_hclocktime);
        } else if (ctl->adjust) {
                if (tdrift.tv_sec > 0 || tdrift.tv_sec < -1)
-                       do_adjustment(ctl, adjtime, hclock_valid,
-                                     hclocktime, read_time);
+                       do_adjustment(ctl, adjtime, hclocktime, read_time);
                else
                        printf(_("Needed adjustment is less than one second, "
                                 "so not setting clock.\n"));
@@ -1123,22 +1068,13 @@ manipulate_clock(const struct hwclock_control *ctl, const time_t set_time,
                set_hardware_clock_exact(ctl, (time_t) reftime.tv_sec, reftime);
                if (!ctl->noadjfile)
                        adjust_drift_factor(ctl, adjtime, nowtime,
-                                           hclock_valid, hclocktime);
+                                           hclocktime);
        } else if (ctl->hctosys) {
-               return set_system_clock(ctl, hclock_valid, hclocktime);
-       } else if (ctl->predict) {
-               hclocktime = time_inc(hclocktime, (double)
-                                     -(tdrift.tv_sec + tdrift.tv_usec / 1E6));
-               if (ctl->debug) {
-                       printf(_
-                              ("At %ld seconds after 1969, RTC is predicted to read %ld seconds after 1969.\n"),
-                              set_time, hclocktime.tv_sec);
-               }
-               display_time(TRUE, hclocktime);
+               return set_system_clock(ctl, hclocktime);
        }
-       if (!ctl->noadjfile)
-               save_adjtime(ctl, adjtime);
-       return 0;
+       if (!ctl->noadjfile && adjtime->dirty)
+               return save_adjtime(ctl, adjtime);
+       return EXIT_SUCCESS;
 }
 
 /**
@@ -1159,11 +1095,9 @@ manipulate_epoch(const struct hwclock_control *ctl)
        } else if (ctl->setepoch) {
                if (!ctl->epoch_option)
                        warnx(_("--epoch is required for --setepoch."));
-               else if (ctl->testing)
-                       printf(_("Test mode: epoch was not set to %s.\n"),
-                              ctl->epoch_option);
-               else if (set_epoch_rtc(ctl))
-                       warnx(_("unable to set the RTC epoch."));
+               else if (!ctl->testing)
+                       if (set_epoch_rtc(ctl))
+                               warnx(_("unable to set the RTC epoch."));
        }
 }
 #endif         /* __linux__ __alpha__ */
@@ -1174,7 +1108,7 @@ static void out_version(void)
 }
 
 static void __attribute__((__noreturn__))
-usage(const struct hwclock_control *ctl)
+usage(void)
 {
        fputs(USAGE_HEADER, stdout);
        printf(_(" %s [function] [option...]\n"), program_invocation_short_name);
@@ -1189,7 +1123,7 @@ usage(const struct hwclock_control *ctl)
        puts(_(" -s, --hctosys        set the system time from the RTC"));
        puts(_(" -w, --systohc        set the RTC from the system time"));
        puts(_("     --systz          send timescale configurations to the kernel"));
-       puts(_("     --adjust         adjust the RTC to account for systematic drift"));
+       puts(_(" -a, --adjust         adjust the RTC to account for systematic drift"));
 #if defined(__linux__) && defined(__alpha__)
        puts(_("     --getepoch       display the RTC epoch"));
        puts(_("     --setepoch       set the RTC epoch according to --epoch"));
@@ -1205,6 +1139,7 @@ usage(const struct hwclock_control *ctl)
        printf(_(
               "     --directisa      use the ISA bus instead of %1$s access\n"), _PATH_RTC_DEV);
        puts(_("     --date <time>    date/time input for --set and --predict"));
+       puts(_("     --delay <sec>    delay used when set new RTC time"));
 #if defined(__linux__) && defined(__alpha__)
        puts(_("     --epoch <year>   epoch input for --setepoch"));
 #endif
@@ -1213,26 +1148,20 @@ usage(const struct hwclock_control *ctl)
               "     --noadjfile      do not use %1$s\n"), _PATH_ADJTIME);
        printf(_(
               "     --adjfile <file> use an alternate file to %1$s\n"), _PATH_ADJTIME);
-       puts(_("     --test           dry run; use -D to view what would have happened"));
-       puts(_(" -D, --debug          use debug mode"));
+       puts(_("     --test           dry run; implies --verbose"));
+       puts(_(" -v, --verbose        display more details"));
        fputs(USAGE_SEPARATOR, stdout);
        printf(USAGE_HELP_OPTIONS(22));
        printf(USAGE_MAN_TAIL("hwclock(8)"));
-       hwclock_exit(ctl, EXIT_SUCCESS);
+       exit(EXIT_SUCCESS);
 }
 
-/*
- * Returns:
- *  EX_USAGE: bad invocation
- *  EX_NOPERM: no permission
- *  EX_OSFILE: cannot open /dev/rtc or /etc/adjtime
- *  EX_IOERR: ioctl error getting or setting the time
- *  0: OK (or not)
- *  1: failure
- */
 int main(int argc, char **argv)
 {
-       struct hwclock_control ctl = { .show = 1 }; /* default op is show */
+       struct hwclock_control ctl = {
+                       .show = 1,              /* default op is show */
+                       .rtc_delay = -1.0       /* unspecified */
+       };
        struct timeval startup_time;
        struct adjtime adjtime = { 0 };
        struct timespec when = { 0 };
@@ -1247,6 +1176,7 @@ int main(int argc, char **argv)
        enum {
                OPT_ADJFILE = CHAR_MAX + 1,
                OPT_DATE,
+               OPT_DELAY,
                OPT_DIRECTISA,
                OPT_EPOCH,
                OPT_GET,
@@ -1267,9 +1197,11 @@ int main(int argc, char **argv)
                { "show",         no_argument,       NULL, 'r'            },
                { "hctosys",      no_argument,       NULL, 's'            },
                { "utc",          no_argument,       NULL, 'u'            },
-               { "version",      no_argument,       NULL, 'v'            },
+               { "version",      no_argument,       NULL, 'V'            },
                { "systohc",      no_argument,       NULL, 'w'            },
                { "debug",        no_argument,       NULL, 'D'            },
+               { "ul-debug",     required_argument, NULL, 'd'            },
+               { "verbose",      no_argument,       NULL, 'v'            },
                { "set",          no_argument,       NULL, OPT_SET        },
 #if defined(__linux__) && defined(__alpha__)
                { "getepoch",     no_argument,       NULL, OPT_GETEPOCH   },
@@ -1280,6 +1212,7 @@ int main(int argc, char **argv)
                { "directisa",    no_argument,       NULL, OPT_DIRECTISA  },
                { "test",         no_argument,       NULL, OPT_TEST       },
                { "date",         required_argument, NULL, OPT_DATE       },
+               { "delay",        required_argument, NULL, OPT_DELAY      },
 #ifdef __linux__
                { "rtc",          required_argument, NULL, 'f'            },
 #endif
@@ -1314,7 +1247,7 @@ int main(int argc, char **argv)
                 * have audit compiled in.
                 */
                warnx(_("Unable to connect to audit system"));
-               return EX_NOPERM;
+               return EXIT_FAILURE;
        }
 #endif
        setlocale(LC_ALL, "");
@@ -1328,16 +1261,22 @@ int main(int argc, char **argv)
 #endif
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        while ((c = getopt_long(argc, argv,
-                               "hvVDalrsuwf:", longopts, NULL)) != -1) {
+                               "hvVDd:alrsuwf:", longopts, NULL)) != -1) {
 
                err_exclusive_options(c, longopts, excl, excl_st);
 
                switch (c) {
                case 'D':
-                       ctl.debug++;
+                       warnx(_("use --verbose, --debug has been deprecated."));
+                       break;
+               case 'v':
+                       ctl.verbose = 1;
+                       break;
+               case 'd':
+                       hwclock_init_debug(optarg);
                        break;
                case 'a':
                        ctl.adjust = 1;
@@ -1390,10 +1329,14 @@ int main(int argc, char **argv)
                        break;
                case OPT_TEST:
                        ctl.testing = 1;        /* --test */
+                       ctl.verbose = 1;
                        break;
                case OPT_DATE:
                        ctl.date_opt = optarg;  /* --date */
                        break;
+               case OPT_DELAY:
+                       ctl.rtc_delay = strtod_or_err(optarg, "invalid --delay argument");
+                       break;
                case OPT_ADJFILE:
                        ctl.adj_file_name = optarg;     /* --adjfile */
                        break;
@@ -1418,20 +1361,19 @@ int main(int argc, char **argv)
                        ctl.rtc_dev_name = optarg;      /* --rtc */
                        break;
 #endif
-               case 'v':                       /* --version */
-               case 'V':
-                       out_version();
-                       return 0;
+
+               case 'V':                       /* --version */
+                       print_version(EXIT_SUCCESS);
                case 'h':                       /* --help */
-                       usage(&ctl);
+                       usage();
                default:
-                       errtryhelp(EX_USAGE);
+                       errtryhelp(EXIT_FAILURE);
                }
        }
 
        if (argc -= optind) {
                warnx(_("%d too many arguments given"), argc);
-               errtryhelp(EX_USAGE);
+               errtryhelp(EXIT_FAILURE);
        }
 
        if (!ctl.adj_file_name)
@@ -1439,37 +1381,40 @@ int main(int argc, char **argv)
 
        if (ctl.update && !ctl.set && !ctl.systohc) {
                warnx(_("--update-drift requires --set or --systohc"));
-               hwclock_exit(&ctl, EX_USAGE);
+               exit(EXIT_FAILURE);
        }
 
        if (ctl.noadjfile && !ctl.utc && !ctl.local_opt) {
                warnx(_("With --noadjfile, you must specify "
                        "either --utc or --localtime"));
-               hwclock_exit(&ctl, EX_USAGE);
+               exit(EXIT_FAILURE);
        }
 
        if (ctl.set || ctl.predict) {
                if (!ctl.date_opt) {
                warnx(_("--date is required for --set or --predict"));
-               hwclock_exit(&ctl, EX_USAGE);
+               exit(EXIT_FAILURE);
                }
                if (parse_date(&when, ctl.date_opt, NULL))
                        set_time = when.tv_sec;
                else {
                        warnx(_("invalid date '%s'"), ctl.date_opt);
-                       hwclock_exit(&ctl, EX_USAGE);
+                       exit(EXIT_FAILURE);
                }
        }
 
 #if defined(__linux__) && defined(__alpha__)
        if (ctl.getepoch || ctl.setepoch) {
                manipulate_epoch(&ctl);
-               hwclock_exit(&ctl, EX_OK);
+               hwclock_exit(&ctl, EXIT_SUCCESS);
        }
 #endif
 
-       if (ctl.debug)
+       if (ctl.verbose) {
                out_version();
+               printf(_("System Time: %ld.%06ld\n"),
+                      startup_time.tv_sec, startup_time.tv_usec);
+       }
 
        if (!ctl.systz && !ctl.predict)
                determine_clock_access_method(&ctl);
@@ -1479,9 +1424,11 @@ int main(int argc, char **argv)
                        hwclock_exit(&ctl, rc);
        } else
                /* Avoid writing adjtime file if we don't have to. */
-               adjtime.dirty = FALSE;
+               adjtime.dirty = 0;
        ctl.universal = hw_clock_is_utc(&ctl, adjtime);
        rc = manipulate_clock(&ctl, set_time, startup_time, &adjtime);
+       if (ctl.testing)
+               puts(_("Test mode: nothing was changed."));
        hwclock_exit(&ctl, rc);
        return rc;              /* Not reached */
 }
@@ -1497,9 +1444,9 @@ hwclock_exit(const struct hwclock_control *ctl
        if (ctl->hwaudit_on && !ctl->testing) {
                audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG,
                                       "op=change-system-time", NULL, NULL, NULL,
-                                      status ? 0 : 1);
-               close(hwaudit_fd);
+                                      status);
        }
+       close(hwaudit_fd);
 #endif
        exit(status);
 }