summaryrefslogtreecommitdiffstats
path: root/clock
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:41 +0100
committerKarel Zak2006-12-07 00:25:41 +0100
commiteb63b9b8f4cecb34c2478282567862bc48ef256d (patch)
tree99243f8eecb44c2bb6a559982b99c680fcb649e7 /clock
parentImported from util-linux-2.9v tarball. (diff)
downloadkernel-qcow2-util-linux-eb63b9b8f4cecb34c2478282567862bc48ef256d.tar.gz
kernel-qcow2-util-linux-eb63b9b8f4cecb34c2478282567862bc48ef256d.tar.xz
kernel-qcow2-util-linux-eb63b9b8f4cecb34c2478282567862bc48ef256d.zip
Imported from util-linux-2.10f tarball.
Diffstat (limited to 'clock')
-rw-r--r--clock/README.hwclock29
-rw-r--r--clock/clock-ppc.c459
-rw-r--r--clock/cmos.c5
-rw-r--r--clock/hwclock.835
-rw-r--r--clock/hwclock.c201
-rw-r--r--clock/kd.c15
6 files changed, 665 insertions, 79 deletions
diff --git a/clock/README.hwclock b/clock/README.hwclock
index 7d2f460dd..ba8bc44c3 100644
--- a/clock/README.hwclock
+++ b/clock/README.hwclock
@@ -2,21 +2,11 @@ Hwclock is a program that runs under Linux and sets and queries the
Hardware Clock, which is often called the Real Time Clock, RTC, or
CMOS clock.
-Hwclock is shipped with an ELF executable built for ISA (Intel)
-machines. So there is nothing to build for those machines. Just
-install the executable file "hwclock" and the man page file
-"hwclock.8" in suitable directories (like /sbin/hwclock and
-/usr/man/man8/hwclock.8) and you're ready to go.
-
-hwclock accesses platform-dependent hardware, so if you have something
-other than an ISA machine, the shipped executable probably doesn't work,
-and you have to compile hwclock yourself.
-
Sometimes, you need to install hwclock setuid root. If you want users
other than the superuser to be able to display the clock value using the
direct ISA I/O method, install it setuid root. If you have the /dev/rtc
-interface on your system or are on a non-ISA system, there's no need for
-users to use the direct ISA I/O method, so don't bother.
+interface on your system or are on a non-ISA system, there's probably
+no need for users to use the direct ISA I/O method, so don't bother.
To install setuid root, do something like this:
@@ -32,15 +22,6 @@ If you want to build hwclock, just cd to the source directory and invoke
make with no parameters.
hwclock calls option processing routines in the libsshopt library,
-which is part of Sverre H. Huseby's "shhopt" package. An ELF
-executable of this library is included in the package, but you can use
-a copy that is already on your system by altering the make file. You
-can find a more authoritative copy of this library, and its source
-code, on sunsite (ftp://sunsite.unc.edu/pub/Linux/libs/shhopt-X.Y).
-
-As shipped, the routines are linked in statically, so you only need the
-libsshopt.a file to build hwclock, not to run it.
-
-
-
-
+which is part of Sverre H. Huseby's "shhopt" package. You
+can find a more authoritative copy of this package on metalab
+(ftp://metalab.unc.edu/pub/Linux/libs/shhopt-X.Y).
diff --git a/clock/clock-ppc.c b/clock/clock-ppc.c
new file mode 100644
index 000000000..6d8969adb
--- /dev/null
+++ b/clock/clock-ppc.c
@@ -0,0 +1,459 @@
+/*
+From t-matsuu@protein.osaka-u.ac.jp Sat Jan 22 13:43:20 2000
+Date: Sat, 22 Jan 2000 21:42:54 +0900 (JST)
+To: Andries.Brouwer@cwi.nl
+Subject: Please merge the source for PPC
+From: MATSUURA Takanori <t-matsuu@protein.osaka-u.ac.jp>
+
+Even now, it is used clock-1.1 based source on Linux for PowerPC
+architecture, attached on this mail.
+
+Please merge this source in main util-linux source.
+
+But I'm not an author of this source, but Paul Mackerras.
+http://linuxcare.com.au/paulus/
+shows details of him.
+
+MATSUURA Takanori @ Division of Protein Chemistry,
+ Institute for Protein Research, Osaka University, Japan
+E-Mail: t-matsuu@protein.osaka-u.ac.jp
+Web Page: http://www.protein.osaka-u.ac.jp/chemistry/matsuura/
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <time.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/time.h>
+
+#include <asm/cuda.h>
+
+/*
+ * Adapted for Power Macintosh by Paul Mackerras.
+ */
+
+/* V1.0
+ * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992
+ *
+ * clock [-u] -r - read cmos clock
+ * clock [-u] -w - write cmos clock from system time
+ * clock [-u] -s - set system time from cmos clock
+ * clock [-u] -a - set system time from cmos clock, adjust the time to
+ * correct for systematic error, and put it back to the cmos.
+ * -u indicates cmos clock is kept in universal time
+ *
+ * The program is designed to run setuid, since we need to be able to
+ * write to the CUDA.
+ *
+ *********************
+ * V1.1
+ * Modified for clock adjustments - Rob Hooft, hooft@chem.ruu.nl, Nov 1992
+ * Also moved error messages to stderr. The program now uses getopt.
+ * Changed some exit codes. Made 'gcc 2.3 -Wall' happy.
+ *
+ * I think a small explanation of the adjustment routine should be given
+ * here. The problem with my machine is that its CMOS clock is 10 seconds
+ * per day slow. With this version of clock.c, and my '/etc/rc.local'
+ * reading '/etc/clock -au' instead of '/etc/clock -u -s', this error
+ * is automatically corrected at every boot.
+ *
+ * To do this job, the program reads and writes the file '/etc/adjtime'
+ * 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
+ *
+ * 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'
+ *
+ * If the adjustment doesn't work for you, try contacting me by E-mail.
+ *
+ ******
+ * V1.2
+ *
+ * Applied patches by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de)
+ * Patched and indented by Rob Hooft (hooft@EMBL-Heidelberg.DE)
+ *
+ * A free quote from a MAIL-message (with spelling corrections):
+ *
+ * "I found the explanation and solution for the CMOS reading 0xff problem
+ * in the 0.99pl13c (ALPHA) kernel: the RTC goes offline for a small amount
+ * of time for updating. Solution is included in the kernel source
+ * (linux/kernel/time.c)."
+ *
+ * "I modified clock.c to fix this problem and added an option (now default,
+ * look for USE_INLINE_ASM_IO) that I/O instructions are used as inline
+ * code and not via /dev/port (still possible via #undef ...)."
+ *
+ * With the new code, which is partially taken from the kernel sources,
+ * the CMOS clock handling looks much more "official".
+ * Thanks Harald (and Torsten for the kernel code)!
+ *
+ ******
+ * V1.3
+ * Canges from alan@spri.levels.unisa.edu.au (Alan Modra):
+ * a) Fix a few typos in comments and remove reference to making
+ * clock -u a cron job. The kernel adjusts cmos time every 11
+ * minutes - see kernel/sched.c and kernel/time.c set_rtc_mmss().
+ * This means we should really have a cron job updating
+ * /etc/adjtime every 11 mins (set last_time to the current time
+ * and not_adjusted to ???).
+ * b) Swapped arguments of outb() to agree with asm/io.h macro of the
+ * same name. Use outb() from asm/io.h as it's slightly better.
+ * c) Changed CMOS_READ and CMOS_WRITE to inline functions. Inserted
+ * cli()..sti() pairs in appropriate places to prevent possible
+ * errors, and changed ioperm() call to iopl() to allow cli.
+ * d) Moved some variables around to localise them a bit.
+ * e) Fixed bug with clock -ua or clock -us that cleared environment
+ * variable TZ. This fix also cured the annoying display of bogus
+ * day of week on a number of machines. (Use mktime(), ctime()
+ * rather than asctime() )
+ * f) Use settimeofday() rather than stime(). This one is important
+ * as it sets the kernel's timezone offset, which is returned by
+ * gettimeofday(), and used for display of MSDOS and OS2 file
+ * times.
+ * g) faith@cs.unc.edu added -D flag for debugging
+ *
+ * V1.4: alan@SPRI.Levels.UniSA.Edu.Au (Alan Modra)
+ * Wed Feb 8 12:29:08 1995, fix for years > 2000.
+ * faith@cs.unc.edu added -v option to print version.
+ *
+ * August 1996 Tom Dyas (tdyas@eden.rutgers.edu)
+ * Converted to be compatible with the SPARC /dev/rtc driver.
+ *
+ */
+
+#define VERSION "1.4"
+
+/* Here the information for time adjustments is kept. */
+#define ADJPATH "/etc/adjtime"
+
+/* Apparently the RTC on PowerMacs stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET 2082844800
+
+/* used for debugging the code. */
+/*#define KEEP_OFF */
+
+/* Globals */
+int readit = 0;
+int adjustit = 0;
+int writeit = 0;
+int setit = 0;
+int universal = 0;
+int debug = 0;
+
+time_t mkgmtime(struct tm *);
+
+volatile void
+usage ( void )
+{
+ (void) fprintf (stderr,
+ "clock [-u] -r|w|s|a|v\n"
+ " r: read and print CMOS clock\n"
+ " w: write CMOS clock from system time\n"
+ " s: set system time from CMOS clock\n"
+ " a: get system time and adjust CMOS clock\n"
+ " u: CMOS clock is in universal time\n"
+ " v: print version (" VERSION ") and exit\n"
+ );
+ exit(EXIT_FAILURE);
+}
+
+int adb_fd;
+
+void
+adb_init ( void )
+{
+ adb_fd = open ("/dev/adb", 2);
+ if (adb_fd < 0)
+ {
+ perror ("unable to open /dev/adb read/write : ");
+ exit(EXIT_FAILURE);
+ }
+}
+
+unsigned char get_packet[2] = { (unsigned char) CUDA_PACKET,
+ (unsigned char) CUDA_GET_TIME };
+unsigned char set_packet[6] = { (unsigned char) CUDA_PACKET,
+ (unsigned char) CUDA_SET_TIME };
+
+int
+main (int argc, char **argv )
+{
+ struct tm tm, *tmp;
+ time_t systime;
+ time_t last_time;
+ time_t clock_time;
+ int i, arg;
+ double factor;
+ double not_adjusted;
+ int adjustment = 0;
+ /* unsigned char save_control, save_freq_select; */
+ unsigned char reply[16];
+
+ while ((arg = getopt (argc, argv, "rwsuaDv")) != -1)
+ {
+ switch (arg)
+ {
+ case 'r':
+ readit = 1;
+ break;
+ case 'w':
+ writeit = 1;
+ break;
+ case 's':
+ setit = 1;
+ break;
+ case 'u':
+ universal = 1;
+ break;
+ case 'a':
+ adjustit = 1;
+ break;
+ case 'D':
+ debug = 1;
+ break;
+ case 'v':
+ (void) fprintf( stderr, "clock " VERSION "\n" );
+ exit(EXIT_SUCCESS);
+ default:
+ usage ();
+ }
+ }
+
+ /* If we are in MkLinux do not even bother trying to set the clock */
+ if(!access("/proc/osfmach3/version", R_OK))
+ { // We're running MkLinux
+ if ( readit | writeit | setit | adjustit )
+ printf("You must change the clock setting in MacOS.\n");
+ exit(0);
+ }
+
+ if (readit + writeit + setit + adjustit > 1)
+ usage (); /* only allow one of these */
+
+ if (!(readit | writeit | setit | adjustit)) /* default to read */
+ readit = 1;
+
+ adb_init ();
+
+ if (adjustit)
+ { /* Read adjustment parameters first */
+ FILE *adj;
+ if ((adj = fopen (ADJPATH, "r")) == NULL)
+ {
+ perror (ADJPATH);
+ exit(EXIT_FAILURE);
+ }
+ if (fscanf (adj, "%lf %d %lf", &factor, (int *) (&last_time),
+ &not_adjusted) < 0)
+ {
+ perror (ADJPATH);
+ exit(EXIT_FAILURE);
+ }
+ (void) fclose (adj);
+ if (debug) (void) printf(
+ "Last adjustment done at %d seconds after 1/1/1970\n",
+ (int) last_time);
+ }
+
+ if (readit || setit || adjustit)
+ {
+ int ii;
+
+ if (write(adb_fd, get_packet, sizeof(get_packet)) < 0) {
+ perror("write adb");
+ exit(EXIT_FAILURE);
+ }
+ ii = (int) read(adb_fd, reply, sizeof(reply));
+ if (ii < 0) {
+ perror("read adb");
+ exit(EXIT_FAILURE);
+ }
+ if (ii != 7)
+ (void) fprintf(stderr,
+ "Warning: bad reply length from CUDA (%d)\n", ii);
+ clock_time = (time_t) ((reply[3] << 24) + (reply[4] << 16)
+ + (reply[5] << 8)) + (time_t) reply[6];
+ clock_time -= RTC_OFFSET;
+
+ if (universal) {
+ systime = clock_time;
+ } else {
+ tm = *gmtime(&clock_time);
+ (void) printf("time in rtc is %s", asctime(&tm));
+ tm.tm_isdst = -1; /* don't know whether it's DST */
+ systime = mktime(&tm);
+ }
+ }
+
+ if (readit)
+ {
+ (void) printf ("%s", ctime (&systime ));
+ }
+
+ if (setit || adjustit)
+ {
+ struct timeval tv;
+ struct timezone tz;
+
+/* program is designed to run setuid, be secure! */
+
+ if (getuid () != 0)
+ {
+ (void) fprintf (stderr,
+ "Sorry, must be root to set or adjust time\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (adjustit)
+ { /* the actual adjustment */
+ double exact_adjustment;
+
+ exact_adjustment = ((double) (systime - last_time))
+ * factor / (24 * 60 * 60)
+ + not_adjusted;
+ if (exact_adjustment > 0.)
+ adjustment = (int) (exact_adjustment + 0.5);
+ else
+ adjustment = (int) (exact_adjustment - 0.5);
+ not_adjusted = exact_adjustment - (double) adjustment;
+ systime += adjustment;
+ if (debug) {
+ (void) printf ("Time since last adjustment is %d seconds\n",
+ (int) (systime - last_time));
+ (void) printf ("Adjusting time by %d seconds\n",
+ adjustment);
+ (void) printf ("remaining adjustment is %.3f seconds\n",
+ not_adjusted);
+ }
+ }
+#ifndef KEEP_OFF
+ tv.tv_sec = systime;
+ tv.tv_usec = 0;
+ tz.tz_minuteswest = timezone / 60;
+ tz.tz_dsttime = daylight;
+
+ if (settimeofday (&tv, &tz) != 0)
+ {
+ (void) fprintf (stderr,
+ "Unable to set time -- probably you are not root\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (debug) {
+ (void) printf( "Called settimeofday:\n" );
+ (void) printf( "\ttv.tv_sec = %ld, tv.tv_usec = %ld\n",
+ tv.tv_sec, tv.tv_usec );
+ (void) printf( "\ttz.tz_minuteswest = %d, tz.tz_dsttime = %d\n",
+ tz.tz_minuteswest, tz.tz_dsttime );
+ }
+#endif
+ }
+
+ if (writeit || (adjustit && adjustment != 0))
+ {
+ systime = time (NULL);
+
+ if (universal) {
+ clock_time = systime;
+
+ } else {
+ tmp = localtime(&systime);
+ clock_time = mkgmtime(tmp);
+ }
+
+ clock_time += RTC_OFFSET;
+ set_packet[2] = clock_time >> 24;
+ set_packet[3] = clock_time >> 16;
+ set_packet[4] = clock_time >> 8;
+ set_packet[5] = (unsigned char) clock_time;
+
+ if (write(adb_fd, set_packet, sizeof(set_packet)) < 0) {
+ perror("write adb (set)");
+ exit(EXIT_FAILURE);
+ }
+ i = (int) read(adb_fd, reply, sizeof(reply));
+ if (debug) {
+ int j;
+ (void) printf("set reply %d bytes:", i);
+ for (j = 0; j < i; ++j)
+ (void) printf(" %.2x", (unsigned int) reply[j]);
+ (void) printf("\n");
+ }
+ if (i != 3 || reply[1] != (unsigned char) 0)
+ (void) fprintf(stderr, "Warning: error %d setting RTC\n",
+ (int) reply[1]);
+
+ if (debug) {
+ clock_time -= RTC_OFFSET;
+ (void) printf("set RTC to %s", asctime(gmtime(&clock_time)));
+ }
+ }
+ else
+ if (debug) (void) printf ("CMOS clock unchanged.\n");
+ /* Save data for next 'adjustit' call */
+ if (adjustit)
+ {
+ FILE *adj;
+ if ((adj = fopen (ADJPATH, "w")) == NULL)
+ {
+ perror (ADJPATH);
+ exit(EXIT_FAILURE);
+ }
+ (void) fprintf (adj, "%f %d %f\n", factor, (int) systime, not_adjusted);
+ (void) fclose (adj);
+ }
+ exit(EXIT_SUCCESS);
+}
+
+/* Stolen from linux/arch/i386/kernel/time.c. */
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+time_t mkgmtime(struct tm *tm)
+{
+ int mon = tm->tm_mon + 1;
+ int year = tm->tm_year + 1900;
+
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12) +
+ tm->tm_mday + year*365 - 719499
+ )*24 + tm->tm_hour /* now have hours */
+ )*60 + tm->tm_min /* now have minutes */
+ )*60 + tm->tm_sec; /* finally seconds */
+}
diff --git a/clock/cmos.c b/clock/cmos.c
index 78d5dbb94..827ec54a9 100644
--- a/clock/cmos.c
+++ b/clock/cmos.c
@@ -146,8 +146,9 @@ set_cmos_epoch(int ARCconsole, int SRM) {
if (debug) printf (_("booted from MILO\n"));
}
- /* See whether we are dealing with a RUFFIAN aka UX, as they have REALLY
- different TOY (TimeOfYear) format: BCD, and not an ARC-style epoch.
+ /* See whether we are dealing with a RUFFIAN aka Alpha PC-164 UX (or BX),
+ as they have REALLY different TOY (TimeOfYear) format: BCD, and not
+ an ARC-style epoch.
BCD is detected dynamically, but we must NOT adjust like ARC. */
if (ARCconsole && is_in_cpuinfo("system type", "Ruffian")) {
ARCconsole = 0;
diff --git a/clock/hwclock.8 b/clock/hwclock.8
index 0a216840a..ddf0c7c3e 100644
--- a/clock/hwclock.8
+++ b/clock/hwclock.8
@@ -2,34 +2,35 @@
.SH NAME
clock \- query and set the hardware clock (RTC)
.SH SYNOPSIS
-.B "hwclock --show"
+.B "hwclock \-\-show"
.br
-.B "hwclock --set --date=newdate"
+.B "hwclock \-\-set \-\-date=newdate"
.br
-.B "hwclock --systohc"
+.B "hwclock \-\-systohc"
.br
-.B "hwclock --hctosys"
+.B "hwclock \-\-hctosys"
.br
-.B "hwclock --getepoch"
+.B "hwclock \-\-getepoch"
.br
-.B "hwclock --setepoch --epoch=year"
+.B "hwclock \-\-setepoch \-\-epoch=year"
.br
-.B "hwclock --adjust"
+.B "hwclock \-\-adjust"
.br
-.B "hwclock --version"
+.B "hwclock \-\-version"
.PP
other options:
.PP
-.B "--utc --localtime --directisa --test --debug"
+.B "\-\-utc \-\-localtime \-\-directisa \-\-test \-\-debug"
.PP
and arcane options for DEC Alpha:
.PP
-.B "--arc --jensen --srm --funky-toy"
+.B "\-\-arc \-\-jensen \-\-srm \-\-funky-toy"
.PP
Minimum unique abbreviations of all options are acceptable.
.PP
-Also, equivalent options -r, -w, -s, -a, -v, -u, -D, -A, -J, -S, and -F
-are accepted for compatibility with the program "clock".
+Also, equivalent options \-r, \-w, \-s, \-a, \-v, \-u,
+\-D, \-A, \-J, \-S, and \-F are accepted for compatibility
+with the program "clock", while \-h asks for a help message.
.SH DESCRIPTION
.I hwclock
@@ -239,7 +240,9 @@ are invalid if you don't have an Alpha and shouldn't be necessary if you
do, because
.I hwclock
should be able to determine by itself what it's
-running on. These options make it possible for
+running on, at least when
+.I /proc
+is mounted. These options make it possible for
.I hwclock
to work even when
its environment does not conform to its expectations and thus it cannot
@@ -259,10 +262,12 @@ automatically.
means you are running on a Jensen model.
.B \-\-arc
-means your machine is running with ARC console time.
+means your machine uses epoch 1980 in its hardware clock, as is commonly
+the case for machines on ARC console (but Ruffians have epoch 1900).
.B \-\-srm
-means your machine is running with SRM console time.
+means your machine uses epoch 1900 in its hardware clock, as is commonly
+the case for machines on SRM console.
.B \-\-funky\-toy
means that on your machine, one has to use the UF bit instead
diff --git a/clock/hwclock.c b/clock/hwclock.c
index a496e0570..8c682380e 100644
--- a/clock/hwclock.c
+++ b/clock/hwclock.c
@@ -75,9 +75,9 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <shhopt.h>
+#include <stdarg.h>
#include "clock.h"
-#include "../version.h"
#include "nls.h"
#define MYNAME "hwclock"
@@ -104,11 +104,19 @@ struct adjtime {
structure is not what's in the disk file (because it has been
updated since read from the disk file).
*/
- bool dirty;
+ bool dirty;
+ /* line 1 */
float drift_factor;
time_t last_adj_time;
float 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. */
};
bool debug;
@@ -189,6 +197,25 @@ time_inc(struct timeval addend, float increment) {
}
+static bool
+hw_clock_is_utc(const bool utc, const bool local_opt,
+ const struct adjtime adjtime) {
+ bool ret;
+
+ if (utc)
+ ret = TRUE; /* --utc explicitly given on command line */
+ else if (local_opt)
+ ret = FALSE; /* --localtime explicitly given */
+ else
+ /* get info from adjtime file - default is local */
+ ret = (adjtime.local_utc == UTC);
+ if (debug)
+ printf(_("Assuming hardware clock is kept in %s time.\n"),
+ ret ? _("UTC") : _("local"));
+ return ret;
+}
+
+
static void
read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
@@ -214,6 +241,7 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
adjtime_p->last_adj_time = 0;
adjtime_p->not_adjusted = 0;
adjtime_p->last_calib_time = 0;
+ adjtime_p->local_utc = UNKNOWN;
*rc_p = 0;
} else {
@@ -224,11 +252,14 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
} else {
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 */
line1[0] = '\0'; /* In case fgets fails */
fgets(line1, sizeof(line1), adjfile);
line2[0] = '\0'; /* In case fgets fails */
fgets(line2, sizeof(line2), adjfile);
+ line3[0] = '\0'; /* In case fgets fails */
+ fgets(line3, sizeof(line3), adjfile);
fclose(adjfile);
@@ -244,6 +275,19 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
&adjtime_p->not_adjusted);
sscanf(line2, "%d", (int *) &adjtime_p->last_calib_time);
+
+ 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"));
+ }
+ }
*rc_p = 0;
}
@@ -254,6 +298,9 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
(int) adjtime_p->last_adj_time);
printf(_("Last calibration done at %d seconds after 1969\n"),
(int) 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"));
}
}
}
@@ -312,7 +359,6 @@ mktime_tz(struct tm tm, const bool universal,
changing the local time zone to UTC.
*/
zone = (char *) getenv("TZ"); /* remember original time zone */
- mktime_result = mktime(&tm);
if (universal) {
/* Set timezone to UTC */
setenv("TZ", "", TRUE);
@@ -340,7 +386,9 @@ mktime_tz(struct tm tm, const bool universal,
*valid_p = TRUE;
*systime_p = mktime_result;
if (debug)
- printf(_("Hw clock time : %.2d:%.2d:%.2d = %d seconds since 1969\n"),
+ printf(_("Hw clock time : %2d/%.2d/%.2d %.2d:%.2d:%.2d = "
+ "%d seconds since 1969\n"),
+ tm.tm_year, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) *systime_p);
}
/* now put back the original zone. */
@@ -578,10 +626,7 @@ set_system_clock(const bool hclock_valid, const time_t 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: do not consider Daylight
- Savings Time to be a separate component of the time zone. Include
- any effect of DST in the basic timezone value and set the kernel
- DST value to 0.
+ 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
@@ -590,7 +635,7 @@ set_system_clock(const bool hclock_valid, const time_t newtime,
If 'testing' is true, don't actually update anything -- just say we
would have.
-----------------------------------------------------------------------------*/
- int retcode; /* our eventual return code */
+ int retcode;
if (!hclock_valid) {
fprintf(stderr,_("The Hardware Clock does not contain a valid time, so "
@@ -598,32 +643,30 @@ set_system_clock(const bool hclock_valid, const time_t newtime,
retcode = 1;
} else {
struct timeval tv;
- int rc; /* local return code */
+ int rc;
tv.tv_sec = newtime;
tv.tv_usec = 0;
- tzset(); /* init timezone, daylight from TZ or ...zoneinfo/localtime */
- /* An undocumented function of tzset() is to set global variabales
- 'timezone' and 'daylight'
- */
+ tzset(); /* init timezone from TZ or ...zoneinfo/localtime */
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 = %ld\n"), timezone/60 - 60*daylight);
+ printf( _("\ttz.tz_minuteswest = %ld\n"), timezone/60);
}
if (testing) {
printf(_("Not setting system clock because running in test mode.\n"));
retcode = 0;
} else {
/* For documentation of settimeofday(), in addition to its man page,
- see kernel/time.c in the Linux source code.
- */
- const struct timezone tz = { timezone/60 - 60*daylight, 0 };
- /* put daylight in minuteswest rather than dsttime,
- since the latter is mostly ignored ... */
+ see kernel/time.c in the Linux source code.
+ The code used to have `-60*daylight' here, but that is wrong.
+ The variable `daylight' does not specify whether it is DST now. */
+
+ const struct timezone tz = { timezone/60, 0 };
+
rc = settimeofday(&tv, &tz);
if (rc != 0) {
if (errno == EPERM)
@@ -744,16 +787,17 @@ save_adjtime(const struct adjtime adjtime, const bool testing) {
But if the contents are clean (unchanged since read from disk), don't
bother.
-----------------------------------------------------------------------------*/
- char newfile[405]; /* Stuff to write to disk file */
+ 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",
+ 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 );
+ (long) adjtime.last_calib_time,
+ (adjtime.local_utc == UTC) ? "UTC" : "LOCAL");
if (testing) {
printf(_("Not updating adjtime file because of testing mode.\n"));
@@ -883,9 +927,8 @@ manipulate_clock(const bool show, const bool adjust,
const bool set, const time_t set_time,
const bool hctosys, const bool systohc,
const struct timeval startup_time,
- const bool universal, const bool testing,
- int *retcode_p
- ) {
+ const bool utc, const bool local_opt,
+ const bool testing, int *retcode_p) {
/*---------------------------------------------------------------------------
Do all the normal work of hwclock - read, set clock, etc.
@@ -902,7 +945,7 @@ manipulate_clock(const bool show, const bool adjust,
if (no_auth) *retcode_p = 1;
else {
- if (adjust || set || systohc)
+ if (adjust || set || systohc || (!utc && !local_opt))
read_adjtime(&adjtime, &rc);
else {
/* A little trick to avoid reading the file if we don't have to */
@@ -911,6 +954,14 @@ manipulate_clock(const bool show, const bool adjust,
}
if (rc != 0) *retcode_p = 2;
else {
+ 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;
+ }
+
synchronize_to_clock_tick(retcode_p);
/* this takes up to 1 second */
if (*retcode_p == 0) {
@@ -1016,6 +1067,66 @@ manipulate_epoch(const bool getepoch, const bool setepoch,
#endif
}
+/*
+ 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"
+ " --help show this help\n"
+ " --show read hardware clock and print result\n"
+ " --set set the rtc to the time given with --date\n"
+ " --hctosys set the system time from the hardware clock\n"
+ " --systohc set the hardware clock to the current system time\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"
+ " --setepoch set the kernel's hardware clock epoch value to the \n"
+ " value given with --epoch\n"
+ " --version print out the version of hwclock to stdout\n"
+ "\nOptions: \n"
+ " --utc the hardware clock is kept in coordinated universal time\n"
+ " --localtime the hardware clock is kept in local time\n"
+ " --directisa access the ISA bus directly instead of /dev/rtc\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"
+ ));
+#ifdef __alpha__
+ fprintf( usageto, _(
+ " --jensen, --arc, --srm, --funky-toy\n"
+ " tell hwclock the type of alpha you have (see hwclock(8))\n"
+ ) );
+#endif
+
+
+ fflush(stdout);
+ if( fmt ) {
+ usageto = stderr;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+
+ exit( fmt ? 99 : 0 );
+}
+
int
main(int argc, char **argv, char **envp) {
@@ -1034,12 +1145,14 @@ main(int argc, char **argv, char **envp) {
are given by the option_def. The only exception is <show>, which
may be modified after parsing is complete to effect an implied option.
*/
- bool show, set, systohc, hctosys, adjust, getepoch, setepoch, version;
- bool ARCconsole, universal, testing, directisa, Jensen, SRM, funky_toy;
+ bool help, show, set, systohc, hctosys, adjust, getepoch, setepoch, version;
+ bool ARCconsole, utc, testing, directisa, Jensen, SRM, funky_toy;
+ bool local_opt;
char *date_opt;
int epoch_opt;
const optStruct option_def[] = {
+ { 'h', (char *) "help", OPT_FLAG, &help, 0 },
{ 'r', (char *) "show", OPT_FLAG, &show, 0 },
{ 0, (char *) "set", OPT_FLAG, &set, 0 },
{ 'w', (char *) "systohc", OPT_FLAG, &systohc, 0 },
@@ -1048,9 +1161,11 @@ main(int argc, char **argv, char **envp) {
{ 0, (char *) "setepoch", OPT_FLAG, &setepoch, 0 },
{ 'a', (char *) "adjust", OPT_FLAG, &adjust, 0 },
{ 'v', (char *) "version", OPT_FLAG, &version, 0 },
+ { 'V', (char *) "version", OPT_FLAG, &version, 0 },
{ 0, (char *) "date", OPT_STRING, &date_opt, 0 },
{ 0, (char *) "epoch", OPT_UINT, &epoch_opt, 0 },
- { 'u', (char *) "utc", OPT_FLAG, &universal, 0 },
+ { 'u', (char *) "utc", OPT_FLAG, &utc, 0 },
+ { 0, (char *) "localtime", OPT_FLAG, &local_opt, 0 },
{ 0, (char *) "badyear", OPT_FLAG, &badyear, 0 },
{ 0, (char *) "directisa", OPT_FLAG, &directisa, 0 },
{ 0, (char *) "test", OPT_FLAG, &testing, 0 },
@@ -1073,8 +1188,8 @@ main(int argc, char **argv, char **envp) {
textdomain(PACKAGE);
/* set option defaults */
- show = set = systohc = hctosys = adjust = getepoch = setepoch =
- version = universal = ARCconsole = SRM = funky_toy =
+ help = show = set = systohc = hctosys = adjust = getepoch = setepoch =
+ version = utc = local_opt = ARCconsole = SRM = funky_toy =
directisa = badyear = Jensen = testing = debug = FALSE;
date_opt = NULL;
epoch_opt = -1;
@@ -1082,8 +1197,8 @@ main(int argc, char **argv, char **envp) {
argc_parse = argc; argv_parse = argv;
optParseOptions(&argc_parse, argv_parse, option_def, 0);
/* Uses and sets argc_parse, argv_parse.
- Sets show, systohc, hctosys, adjust, universal, version, testing,
- debug, set, date_opt, getepoch, setepoch, epoch_opt
+ Sets show, systohc, hctosys, adjust, utc, local_opt, version,
+ testing, debug, set, date_opt, getepoch, setepoch, epoch_opt
*/
/* This is an ugly routine - for example, if I give an incorrect
option, it only says "unrecognized option" without telling
@@ -1091,12 +1206,14 @@ main(int argc, char **argv, char **envp) {
getopt() and usage() and throw shhopt out. */
if (argc_parse - 1 > 0) {
- fprintf(stderr, _("%s takes no non-option arguments. "
+ usage( _("%s takes no non-option arguments. "
"You supplied %d.\n"),
MYNAME, argc_parse - 1);
- exit(100);
}
+ if (help)
+ usage( NULL );
+
if (show + set + systohc + hctosys + adjust +
getepoch + setepoch + version > 1) {
fprintf(stderr, _("You have specified multiple function options.\n"
@@ -1104,6 +1221,12 @@ main(int argc, char **argv, char **envp) {
exit(100);
}
+ if (utc && local_opt) {
+ fprintf(stderr, _("%s: The --utc and --localtime options are mutually "
+ "exclusive. You specified both.\n"), MYNAME);
+ exit(100);
+ }
+
#ifdef __alpha__
set_cmos_epoch(ARCconsole, SRM);
set_cmos_access(Jensen, funky_toy);
@@ -1145,6 +1268,8 @@ main(int argc, char **argv, char **envp) {
} else if (getepoch || setepoch) {
manipulate_epoch(getepoch, setepoch, epoch_opt, testing);
} else {
+ if (debug)
+ printf(MYNAME " " VERSION "/%s\n",util_linux_version);
determine_clock_access_method(directisa);
if (!ur)
fprintf(stderr, _("Cannot access the Hardware Clock via any known "
@@ -1152,7 +1277,7 @@ main(int argc, char **argv, char **envp) {
"search for an access method.\n"));
else
manipulate_clock(show, adjust, set, set_time, hctosys, systohc,
- startup_time, universal, testing, &rc);
+ startup_time, utc, local_opt, testing, &rc);
}
}
exit(retcode);
@@ -1161,7 +1286,7 @@ main(int argc, char **argv, char **envp) {
/* A single routine for greater uniformity */
void
outsyserr(char *msg) {
- fprintf(stderr, _("%s: %s, errno=%d: %s.\n"),
+ fprintf(stderr, "%s: %s, errno=%d: %s.\n",
progname, msg, errno, strerror(errno));
}
diff --git a/clock/kd.c b/clock/kd.c
index 9ec91f005..d1c4aca19 100644
--- a/clock/kd.c
+++ b/clock/kd.c
@@ -3,6 +3,7 @@
#include <fcntl.h> /* for O_RDONLY */
#include <sys/ioctl.h>
+#include "../defines.h" /* for HAVE_nanosleep */
#include "clock.h"
#include "nls.h"
@@ -46,6 +47,20 @@ synchronize_to_clock_tick_kd(void) {
i = 0;
do {
+ /* Added by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
+ /* "The culprit is the fast loop with KDGHWCLK ioctls. It seems
+ the kernel gets confused by those on Amigas with A2000 RTCs
+ and simply hangs after some time. Inserting a nanosleep helps." */
+ /* Christian T. Steigies: 1 instead of 1000000 is still sufficient
+ to keep the machine from freezing. */
+
+#ifdef HAVE_nanosleep
+ struct timespec sleep = { 0, 1 };
+ nanosleep( &sleep, NULL );
+#else
+ usleep(1);
+#endif
+
if (i++ >= 1000000) {
fprintf(stderr, _("Timed out waiting for time change.\n"));
return 2;