Re: [PATCH] hwclock: add --systz option to set system clock from itself

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

 



On Tue, 2009-03-03 at 10:25 +0100, Karel Zak wrote:

> > Should I rework the patch to do this?
> 
>  Yes, please. Thanks!
> 
Tested and attached.

btw. I'm correct in believing that hwclock doesn't actually use the
values in /etc/adjtime unless --adjust is given, right?

Scott
-- 
Scott James Remnant
scott@xxxxxxxxxx
From a8d34ab764718f403954b6de8ea3730618cd4095 Mon Sep 17 00:00:00 2001
From: Scott James Remnant <scott@xxxxxxxxxx>
Date: Wed, 4 Mar 2009 17:10:43 +0000
Subject: [PATCH] hwclock: add --systz option to set system clock from itself

Since the system clock time is already set from the hardware clock by
the kernel, there's no particular need to read the hardware clock
again.

This option sets the system clock using itself as a reference if the
hardware clock was in local time.  The resulting system clock time
is in UTC, with the kernel timezone set to the difference.

Signed-off-by: Scott James Remnant <scott@xxxxxxxxxx>
---
 hwclock/hwclock.8 |   19 +++++++++
 hwclock/hwclock.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 121 insertions(+), 9 deletions(-)

diff --git a/hwclock/hwclock.8 b/hwclock/hwclock.8
index 31eda21..7f0c53d 100644
--- a/hwclock/hwclock.8
+++ b/hwclock/hwclock.8
@@ -54,6 +54,25 @@ This is a good option to use in one of the system startup scripts.
 .B \-w, \-\-systohc
 Set the Hardware Clock to the current System Time.
 .TP
+.B \-\-systz
+Reset the System Time based on the current timezone.
+
+Also set the kernel's timezone value to the local timezone
+as indicated by the TZ environment variable and/or
+.IR /usr/share/zoneinfo ,
+as
+.BR tzset (3)
+would interpret them.
+The obsolete tz_dsttime field of the kernel's timezone value is set
+to DST_NONE. (For details on what this field used to mean, see
+.BR settimeofday (2).)
+
+This is an alternate option to
+.B \-\-hctosys
+that does not read the hardware clock, and may be used in system startup
+scripts for recent 2.6 kernels where you know the System Time contains
+the Hardware Clock time.
+.TP
 .B \-\-adjust
 Add or subtract time from the Hardware Clock to account for systematic
 drift since the last time the clock was set or adjusted.  See discussion
diff --git a/hwclock/hwclock.c b/hwclock/hwclock.c
index 2749c0f..c4bd1be 100644
--- a/hwclock/hwclock.c
+++ b/hwclock/hwclock.c
@@ -753,6 +753,82 @@ set_system_clock(const bool hclock_valid, const time_t newtime,
 }
 
 
+static int
+set_system_clock_timezone(const bool testing) {
+/*----------------------------------------------------------------------------
+   Reset the System Clock from local time to UTC, based on its current
+   value and the timezone.
+
+   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);
+#ifdef HAVE_TM_GMTOFF
+  minuteswest = -broken->tm_gmtoff/60;		/* GNU extension */
+#else
+  minuteswest = timezone/60;
+  if (broken->tm_isdst)
+	  minuteswest -= 60;
+#endif
+
+  gettimeofday(&tv, NULL);
+  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;
+}
+
+
 static void
 adjust_drift_factor(struct adjtime *adjtime_p,
                     const time_t nowtime,
@@ -1045,7 +1121,7 @@ determine_clock_access_method(const bool user_requests_ISA) {
 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 hctosys, const bool systohc, const bool systz,
                  const struct timeval startup_time,
                  const bool utc, const bool local_opt,
 		 const bool testing) {
@@ -1065,7 +1141,7 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile,
     if (no_auth)
 	  return EX_NOPERM;
 
-    if (!noadjfile && (adjust || set || systohc || (!utc && !local_opt))) {
+    if (!noadjfile && (adjust || set || systohc || systz || (!utc && !local_opt))) {
       rc = read_adjtime(&adjtime);
       if (rc)
 	      return rc;
@@ -1099,7 +1175,7 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile,
              Defined only if hclock_valid is true.
              */
 
-       if (show || adjust || hctosys || !noadjfile) {
+	if (show || adjust || hctosys || (!noadjfile && !systz)) {
           /* data from HW-clock are required */
           rc = synchronize_to_clock_tick();
           if (rc && rc != 2)		/* 2= synchronization timeout */
@@ -1143,6 +1219,16 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile,
             printf(_("Unable to set system clock.\n"));
 	    return rc;
           }
+	} else if (systz) {
+	  if (!universal) {
+	    rc = set_system_clock_timezone(testing);
+	    if (rc) {
+	      printf(_("Unable to set system clock.\n"));
+	      return rc;
+	    }
+	  } else if (debug) {
+	    printf(_("Clock in UTC, not changed.\n"));
+	  }
         }
         if (!noadjfile)
          save_adjtime(adjtime, testing);
@@ -1232,6 +1318,7 @@ usage( const char *fmt, ... ) {
 	"       --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 only\n"
 	"       --adjust       adjust the rtc to account for systematic drift since\n"
 	"                      the clock was last set or adjusted\n"
 	"       --getepoch     print out the kernel's hardware clock epoch value\n"
@@ -1305,6 +1392,7 @@ static const struct option longopts[] = {
 	{ "epoch", 1, 0, 137 },
 	{ "rtc", 1, 0, 'f' },
 	{ "adjfile", 1, 0, 138 },
+	{ "systz", 0, 0, 139 },
 	{ NULL, 0, 0, 0 }
 };
 
@@ -1330,7 +1418,7 @@ main(int argc, char **argv) {
 
 	/* 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, adjust, getepoch, setepoch;
+	bool show, set, systohc, hctosys, systz, adjust, getepoch, setepoch;
 	bool utc, testing, local_opt, noadjfile, directisa;
 	bool ARCconsole, Jensen, SRM, funky_toy;
 	char *date_opt;
@@ -1360,7 +1448,7 @@ main(int argc, char **argv) {
 	textdomain(PACKAGE);
 
 	/* Set option defaults */
-	show = set = systohc = hctosys = adjust = noadjfile = FALSE;
+	show = set = systohc = hctosys = systz = adjust = noadjfile = FALSE;
 	getepoch = setepoch = utc = local_opt = testing = debug = FALSE;
 	ARCconsole = Jensen = SRM = funky_toy = directisa = badyear = FALSE;
 	date_opt = NULL;
@@ -1433,6 +1521,9 @@ main(int argc, char **argv) {
 		case 138:
 			adj_file_name = optarg;		/* --adjfile */
 			break;
+		case 139:
+			systz = TRUE;			/* --systz */
+			break;
 		case 'f':
 			rtc_dev_name = optarg;		/* --rtc */
 			break;
@@ -1464,7 +1555,8 @@ main(int argc, char **argv) {
 		      MYNAME, argc);
 	}
 
-	if (show + set + systohc + hctosys + adjust + getepoch + setepoch > 1){
+	if (show + set + systohc + hctosys + systz + adjust + getepoch
+	    + setepoch > 1){
 		fprintf(stderr, _("You have specified multiple functions.\n"
 				  "You can only perform one function "
 				  "at a time.\n"));
@@ -1515,7 +1607,8 @@ main(int argc, char **argv) {
 		}
 	}
 
-	if (!(show | set | systohc | hctosys | adjust | getepoch | setepoch))
+	if (!(show | set | systohc | hctosys | systz | adjust | getepoch
+	      | setepoch))
 		show = 1; /* default to show */
 
 
@@ -1528,7 +1621,7 @@ main(int argc, char **argv) {
 				_("Sorry, only the superuser can change "
 				  "the Hardware Clock.\n"));
 			permitted = FALSE;
-		} else if (hctosys) {
+		} else if (systz || hctosys) {
 			fprintf(stderr,
 				_("Sorry, only the superuser can change "
 				  "the System Clock.\n"));
@@ -1565,7 +1658,7 @@ main(int argc, char **argv) {
 	}
 
 	rc = manipulate_clock(show, adjust, noadjfile, set, set_time,
-				hctosys, systohc, startup_time, utc,
+				hctosys, systohc, systz, startup_time, utc,
 				local_opt, testing);
 	hwclock_exit(rc);
 	return rc;	/* Not reached */
-- 
1.6.0.5

Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux