diff options
author | Karel Zak | 2006-12-07 00:25:41 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:41 +0100 |
commit | eb63b9b8f4cecb34c2478282567862bc48ef256d (patch) | |
tree | 99243f8eecb44c2bb6a559982b99c680fcb649e7 /clock | |
parent | Imported from util-linux-2.9v tarball. (diff) | |
download | kernel-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.hwclock | 29 | ||||
-rw-r--r-- | clock/clock-ppc.c | 459 | ||||
-rw-r--r-- | clock/cmos.c | 5 | ||||
-rw-r--r-- | clock/hwclock.8 | 35 | ||||
-rw-r--r-- | clock/hwclock.c | 201 | ||||
-rw-r--r-- | clock/kd.c | 15 |
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), + ¬_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; |