diff --git a/hwclock/clock.h b/hwclock/clock.h index e4eb7eba8..8d1befe8f 100644 --- a/hwclock/clock.h +++ b/hwclock/clock.h @@ -1,20 +1,20 @@ #ifndef HWCLOCK_CLOCK_H #define HWCLOCK_CLOCK_H +#include #include #include #include -#include /* for errno, EPERM, EINVAL, ENOENT */ #include #include "c.h" struct clock_ops { char *interface_name; - int (*get_permissions)(void); - int (*read_hardware_clock)(struct tm *tm); - int (*set_hardware_clock)(const struct tm *tm); - int (*synchronize_to_clock_tick)(void); + int (*get_permissions) (void); + int (*read_hardware_clock) (struct tm * tm); + int (*set_hardware_clock) (const struct tm * tm); + int (*synchronize_to_clock_tick) (void); }; extern struct clock_ops *probe_for_cmos_clock(void); @@ -29,9 +29,9 @@ extern int debug; extern int epoch_option; extern void outsyserr(char *msg, ...) #ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))); + __attribute__ ((format(printf, 1, 2))); #else - ; + ; #endif extern double time_diff(struct timeval subtrahend, struct timeval subtractor); /* cmos.c */ @@ -50,4 +50,4 @@ extern void hwaudit_exit(int status); # define hwclock_exit(_status) exit(_status) #endif -#endif /* HWCLOCK_CLOCK_H */ +#endif /* HWCLOCK_CLOCK_H */ diff --git a/hwclock/cmos.c b/hwclock/cmos.c index 0178ef7d3..d6216717f 100644 --- a/hwclock/cmos.c +++ b/hwclock/cmos.c @@ -1,47 +1,48 @@ /* - * i386 CMOS starts out with 14 bytes clock data - * alpha has something similar, but with details - * depending on the machine type. + * i386 CMOS starts out with 14 bytes clock data alpha has something + * similar, but with details depending on the machine type. * - * byte 0: seconds (0-59) - * byte 2: minutes (0-59) - * byte 4: hours (0-23 in 24hr mode, - * 1-12 in 12hr mode, with high bit unset/set if am/pm) - * byte 6: weekday (1-7, Sunday=1) - * byte 7: day of the month (1-31) - * byte 8: month (1-12) - * byte 9: year (0-99) - * Numbers are stored in BCD/binary if bit 2 of byte 11 is unset/set - * The clock is in 12hr/24hr mode if bit 1 of byte 11 is unset/set - * The clock is undefined (being updated) if bit 7 of byte 10 is set. - * The clock is frozen (to be updated) by setting bit 7 of byte 11 - * Bit 7 of byte 14 indicates whether the CMOS clock is reliable: - * it is 1 if RTC power has been good since this bit was last read; - * it is 0 when the battery is dead and system power has been off. + * byte 0: seconds 0-59 + * byte 2: minutes 0-59 + * byte 4: hours 0-23 in 24hr mode, + * 1-12 in 12hr mode, with high bit unset/set + * if am/pm. + * byte 6: weekday 1-7, Sunday=1 + * byte 7: day of the month 1-31 + * byte 8: month 1-12 + * byte 9: year 0-99 * - * Avoid setting the RTC clock within 2 seconds of the day rollover - * that starts a new month or enters daylight saving time. + * Numbers are stored in BCD/binary if bit 2 of byte 11 is unset/set The + * clock is in 12hr/24hr mode if bit 1 of byte 11 is unset/set The clock is + * undefined (being updated) if bit 7 of byte 10 is set. The clock is frozen + * (to be updated) by setting bit 7 of byte 11 Bit 7 of byte 14 indicates + * whether the CMOS clock is reliable: it is 1 if RTC power has been good + * since this bit was last read; it is 0 when the battery is dead and system + * power has been off. + * + * Avoid setting the RTC clock within 2 seconds of the day rollover that + * starts a new month or enters daylight saving time. * * The century situation is messy: - * Usually byte 50 (0x32) gives the century (in BCD, so 19 or 20 hex), - * but IBM PS/2 has (part of) a checksum there and uses byte 55 (0x37). - * Sometimes byte 127 (0x7f) or Bank 1, byte 0x48 gives the century. - * The original RTC will not access any century byte; some modern - * versions will. If a modern RTC or BIOS increments the century byte - * it may go from 0x19 to 0x20, but in some buggy cases 0x1a is produced. + * + * Usually byte 50 (0x32) gives the century (in BCD, so 19 or 20 hex), but + * IBM PS/2 has (part of) a checksum there and uses byte 55 (0x37). + * Sometimes byte 127 (0x7f) or Bank 1, byte 0x48 gives the century. The + * original RTC will not access any century byte; some modern versions will. + * If a modern RTC or BIOS increments the century byte it may go from 0x19 + * to 0x20, but in some buggy cases 0x1a is produced. */ - /* * A struct tm has int fields - * tm_sec (0-59, 60 or 61 only for leap seconds) - * tm_min (0-59) - * tm_hour (0-23) - * tm_mday (1-31) - * tm_mon (0-11) - * tm_year (number of years since 1900) - * tm_wday (0-6, 0=Sunday) - * tm_yday (0-365) - * tm_isdst (>0: yes, 0: no, <0: unknown) + * tm_sec 0-59, 60 or 61 only for leap seconds + * tm_min 0-59 + * tm_hour 0-23 + * tm_mday 1-31 + * tm_mon 0-11 + * tm_year number of years since 1900 + * tm_wday 0-6, 0=Sunday + * tm_yday 0-365 + * tm_isdst >0: yes, 0: no, <0: unknown */ #include /* for geteuid() */ @@ -50,27 +51,40 @@ #include "nls.h" #if defined(__i386__) - # ifdef HAVE_SYS_IO_H -# include +# include # elif defined(HAVE_ASM_IO_H) -# include /* for inb, outb */ +# include /* for inb, outb */ # else -/* Disable cmos access; we can no longer use asm/io.h, since - * the kernel does not export that header. */ -# undef __i386__ -void outb(int a, int b){} -int inb(int c){ return 0; } -# endif +/* + * Disable cmos access; we can no longer use asm/io.h, since the kernel does + * not export that header. + */ +#undef __i386__ +void outb(int a, int b) +{ +} + +int inb(int c) +{ + return 0; +} +#endif /* __i386__ */ #elif defined(__alpha__) /* fails to compile, probably because of u8 etc */ -extern unsigned int inb(unsigned long port); -extern void outb(unsigned char b,unsigned long port); +extern unsigned int inb(unsigned long port); +extern void outb(unsigned char b, unsigned long port); #else -void outb(int a, int b){} -int inb(int c){ return 0; } -#endif +void outb(int a, int b) +{ +} + +int inb(int c) +{ + return 0; +} +#endif /* __alpha__ */ #include "clock.h" @@ -80,39 +94,40 @@ int inb(int c){ return 0; } /* * The epoch. * - * Unix uses 1900 as epoch for a struct tm, and 1970 for a time_t. - * But what was written to CMOS? - * Digital DECstations use 1928 - this is on a mips or alpha - * Digital Unix uses 1952, e.g. on AXPpxi33 - * Windows NT uses 1980. - * The ARC console expects to boot Windows NT and uses 1980. - * (But a Ruffian uses 1900, just like SRM.) - * It is reported that ALPHA_PRE_V1_2_SRM_CONSOLE uses 1958. + * Unix uses 1900 as epoch for a struct tm, and 1970 for a time_t. But what + * was written to CMOS? + * + * Digital DECstations use 1928 - this is on a mips or alpha Digital Unix + * uses 1952, e.g. on AXPpxi33. Windows NT uses 1980. The ARC console + * expects to boot Windows NT and uses 1980. (But a Ruffian uses 1900, just + * like SRM.) It is reported that ALPHA_PRE_V1_2_SRM_CONSOLE uses 1958. */ #define TM_EPOCH 1900 int cmos_epoch = 1900; -/* Martin Ostermann writes: -The problem with the Jensen is twofold: First, it has the clock at a -different address. Secondly, it has a distinction beween "local" and -normal bus addresses. The local ones pertain to the hardware integrated -into the chipset, like serial/parallel ports and of course, the RTC. -Those need to be addressed differently. This is handled fine in the kernel, -and it's not a problem, since this usually gets totally optimized by the -compile. But the i/o routines of (g)libc lack this support so far. -The result of this is, that the old clock program worked only on the -Jensen when USE_DEV_PORT was defined, but not with the normal inb/outb -functions. +/* + * Martin Ostermann writes: + * + * The problem with the Jensen is twofold: First, it has the clock at a + * different address. Secondly, it has a distinction beween "local" and + * normal bus addresses. The local ones pertain to the hardware integrated + * into the chipset, like serial/parallel ports and of course, the RTC. + * Those need to be addressed differently. This is handled fine in the + * kernel, and it's not a problem, since this usually gets totally optimized + * by the compile. But the i/o routines of (g)libc lack this support so far. + * The result of this is, that the old clock program worked only on the + * Jensen when USE_DEV_PORT was defined, but not with the normal inb/outb + * functions. */ int use_dev_port = 0; /* 1 for Jensen */ int dev_port_fd; unsigned short clock_ctl_addr = 0x70; /* 0x170 for Jensen */ -unsigned short clock_data_addr = 0x71; /* 0x171 for Jensen */ - +unsigned short clock_data_addr = 0x71; /* 0x171 for Jensen */ int century_byte = 0; /* 0: don't access a century byte - 50 (0x32): usual PC value - 55 (0x37): PS/2 */ + * 50 (0x32): usual PC value + * 55 (0x37): PS/2 + */ #ifdef __alpha__ int funkyTOY = 0; /* 1 for PC164/LX164/SX164 type alpha */ @@ -120,217 +135,242 @@ int funkyTOY = 0; /* 1 for PC164/LX164/SX164 type alpha */ #ifdef __alpha -static int -is_in_cpuinfo(char *fmt, char *str) +static int is_in_cpuinfo(char *fmt, char *str) { - FILE *cpuinfo; - char field[256]; - char format[256]; - int found = 0; + FILE *cpuinfo; + char field[256]; + char format[256]; + int found = 0; - sprintf(format, "%s : %s", fmt, "%255s"); + sprintf(format, "%s : %s", fmt, "%255s"); - if ((cpuinfo = fopen ("/proc/cpuinfo", "r")) != NULL) { - while (!feof(cpuinfo)) { - if (fscanf (cpuinfo, format, field) == 1) { - if (strncmp(field, str, strlen(str)) == 0) - found = 1; - break; - } - fgets (field, 256, cpuinfo); + if ((cpuinfo = fopen("/proc/cpuinfo", "r")) != NULL) { + while (!feof(cpuinfo)) { + if (fscanf(cpuinfo, format, field) == 1) { + if (strncmp(field, str, strlen(str)) == 0) + found = 1; + break; + } + fgets(field, 256, cpuinfo); + } + fclose(cpuinfo); } - fclose(cpuinfo); - } - return found; + return found; } -/* Set cmos_epoch, either from user options, or by asking the kernel, - or by looking at /proc/cpu_info */ -void -set_cmos_epoch(int ARCconsole, int SRM) { - unsigned long epoch; +/* + * Set cmos_epoch, either from user options, or by asking the kernel, or by + * looking at /proc/cpu_info + */ +void set_cmos_epoch(int ARCconsole, int SRM) +{ + unsigned long epoch; - /* Believe the user */ - if (epoch_option != -1) { - cmos_epoch = epoch_option; - return; - } + /* Believe the user */ + if (epoch_option != -1) { + cmos_epoch = epoch_option; + return; + } - if (ARCconsole) - cmos_epoch = 1980; - - if (ARCconsole || SRM) - return; + if (ARCconsole) + cmos_epoch = 1980; + if (ARCconsole || SRM) + return; #ifdef __linux__ - /* If we can ask the kernel, we don't need guessing from /proc/cpuinfo */ - if (get_epoch_rtc(&epoch, 1) == 0) { - cmos_epoch = epoch; - return; - } + /* + * If we can ask the kernel, we don't need guessing from + * /proc/cpuinfo + */ + if (get_epoch_rtc(&epoch, 1) == 0) { + cmos_epoch = epoch; + return; + } #endif - /* The kernel source today says: read the year. - If it is in 0-19 then the epoch is 2000. - If it is in 20-47 then the epoch is 1980. - If it is in 48-69 then the epoch is 1952. - If it is in 70-99 then the epoch is 1928. - Otherwise the epoch is 1900. - Clearly, this must be changed before 2019. */ + /* + * The kernel source today says: read the year. + * + * If it is in 0-19 then the epoch is 2000. + * If it is in 20-47 then the epoch is 1980. + * If it is in 48-69 then the epoch is 1952. + * If it is in 70-99 then the epoch is 1928. + * + * Otherwise the epoch is 1900. + * TODO: Clearly, this must be changed before 2019. + */ + /* + * See whether we are dealing with SRM or MILO, as they have + * different "epoch" ideas. + */ + if (is_in_cpuinfo("system serial number", "MILO")) { + ARCconsole = 1; + if (debug) + printf(_("booted from MILO\n")); + } - /* See whether we are dealing with SRM or MILO, as they have - different "epoch" ideas. */ - if (is_in_cpuinfo("system serial number", "MILO")) { - ARCconsole = 1; - if (debug) printf (_("booted from MILO\n")); - } + /* + * 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; + if (debug) + printf(_("Ruffian BCD clock\n")); + } - /* 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; - if (debug) printf (_("Ruffian BCD clock\n")); - } - - if (ARCconsole) - cmos_epoch = 1980; + if (ARCconsole) + cmos_epoch = 1980; } -void -set_cmos_access(int Jensen, int funky_toy) { +void set_cmos_access(int Jensen, int funky_toy) +{ - /* See whether we're dealing with a Jensen---it has a weird I/O - system. DEC was just learning how to build Alpha PCs. */ - if (Jensen || is_in_cpuinfo("system type", "Jensen")) { - use_dev_port = 1; - clock_ctl_addr = 0x170; - clock_data_addr = 0x171; - if (debug) printf (_("clockport adjusted to 0x%x\n"), clock_ctl_addr); - } + /* + * See whether we're dealing with a Jensen---it has a weird I/O + * system. DEC was just learning how to build Alpha PCs. + */ + if (Jensen || is_in_cpuinfo("system type", "Jensen")) { + use_dev_port = 1; + clock_ctl_addr = 0x170; + clock_data_addr = 0x171; + if (debug) + printf(_("clockport adjusted to 0x%x\n"), + clock_ctl_addr); + } - /* see whether we are dealing with PC164/LX164/SX164, as they have a TOY - that must be accessed differently to work correctly. */ - /* Nautilus stuff reported by Neoklis Kyriazis */ - if (funky_toy || - is_in_cpuinfo("system variation", "PC164") || - is_in_cpuinfo("system variation", "LX164") || - is_in_cpuinfo("system variation", "SX164") || - is_in_cpuinfo("system type", "Nautilus")) { - funkyTOY = 1; - if (debug) printf (_("funky TOY!\n")); - } + /* + * See whether we are dealing with PC164/LX164/SX164, as they have a + * TOY that must be accessed differently to work correctly. + */ + /* Nautilus stuff reported by Neoklis Kyriazis */ + if (funky_toy || + is_in_cpuinfo("system variation", "PC164") || + is_in_cpuinfo("system variation", "LX164") || + is_in_cpuinfo("system variation", "SX164") || + is_in_cpuinfo("system type", "Nautilus")) { + funkyTOY = 1; + if (debug) + printf(_("funky TOY!\n")); + } } -#endif - +#endif /* __alpha */ #if __alpha__ /* - * The Alpha doesn't allow user-level code to disable interrupts (for - * good reasons). Instead, we ensure atomic operation by performing - * the operation and checking whether the high 32 bits of the cycle - * counter changed. If they did, a context switch must have occurred - * and we redo the operation. As long as the operation is reasonably - * short, it will complete atomically, eventually. + * The Alpha doesn't allow user-level code to disable interrupts (for good + * reasons). Instead, we ensure atomic operation by performing the operation + * and checking whether the high 32 bits of the cycle counter changed. If + * they did, a context switch must have occurred and we redo the operation. + * As long as the operation is reasonably short, it will complete + * atomically, eventually. */ - static unsigned long -atomic(const char *name, unsigned long (*op)(unsigned long), - unsigned long arg) +atomic(const char *name, unsigned long (*op) (unsigned long), unsigned long arg) { - unsigned long ts1, ts2, n, v; + unsigned long ts1, ts2, n, v; - for (n = 0; n < 1000; ++n) { - asm volatile ("rpcc %0" : "r="(ts1)); - v = (*op)(arg); - asm volatile ("rpcc %0" : "r="(ts2)); + for (n = 0; n < 1000; ++n) { + asm volatile ("rpcc %0":"r=" (ts1)); + v = (*op) (arg); + asm volatile ("rpcc %0":"r=" (ts2)); - if ((ts1 ^ ts2) >> 32 == 0) { - return v; - } - } - fprintf(stderr, _("%s: atomic %s failed for 1000 iterations!"), progname, name); - exit(1); + if ((ts1 ^ ts2) >> 32 == 0) { + return v; + } + } + fprintf(stderr, _("%s: atomic %s failed for 1000 iterations!"), + progname, name); + exit(1); } #else /* - * Hmmh, this isn't very atomic. Maybe we should force an error - * instead? + * Hmmh, this isn't very atomic. Maybe we should force an error instead? * - * TODO: optimize the access to CMOS by mlockall(MCL_CURRENT) - * and SCHED_FIFO + * TODO: optimize the access to CMOS by mlockall(MCL_CURRENT) and SCHED_FIFO */ static unsigned long -atomic(const char *name, unsigned long (*op)(unsigned long), - unsigned long arg) +atomic(const char *name, unsigned long (*op) (unsigned long), unsigned long arg) { - return (*op)(arg); + return (*op) (arg); } #endif - -static inline -unsigned long cmos_read(unsigned long reg) +static inline unsigned long cmos_read(unsigned long reg) { - if (use_dev_port) { - unsigned char v = reg | 0x80; - lseek(dev_port_fd, clock_ctl_addr, 0); - if (write(dev_port_fd, &v, 1) == -1 && debug) - printf(_("cmos_read(): write to control address %X failed: %s\n"), clock_ctl_addr, strerror(errno)); - lseek(dev_port_fd, clock_data_addr, 0); - if (read(dev_port_fd, &v, 1) == -1 && debug) - printf(_("cmos_read(): read data address %X failed: %s\n"), clock_data_addr, strerror(errno)); - return v; - } else { - /* We only want to read CMOS data, but unfortunately - writing to bit 7 disables (1) or enables (0) NMI; - since this bit is read-only we have to guess the old status. - Various docs suggest that one should disable NMI while - reading/writing CMOS data, and enable it again afterwards. - This would yield the sequence - outb (reg | 0x80, 0x70); - val = inb(0x71); - outb (0x0d, 0x70); // 0x0d: random read-only location - Other docs state that "any write to 0x70 should be followed - by an action to 0x71 or the RTC wil be left in an unknown state". - Most docs say that it doesnt matter at all what one does. - */ - /* bit 0x80: disable NMI while reading - should we? - Let us follow the kernel and not disable. - Called only with 0 <= reg < 128 */ - outb (reg, clock_ctl_addr); - return inb (clock_data_addr); - } + if (use_dev_port) { + unsigned char v = reg | 0x80; + lseek(dev_port_fd, clock_ctl_addr, 0); + if (write(dev_port_fd, &v, 1) == -1 && debug) + printf(_ + ("cmos_read(): write to control address %X failed: %s\n"), + clock_ctl_addr, strerror(errno)); + lseek(dev_port_fd, clock_data_addr, 0); + if (read(dev_port_fd, &v, 1) == -1 && debug) + printf(_ + ("cmos_read(): read data address %X failed: %s\n"), + clock_data_addr, strerror(errno)); + return v; + } else { + /* + * We only want to read CMOS data, but unfortunately writing + * to bit 7 disables (1) or enables (0) NMI; since this bit + * is read-only we have to guess the old status. Various + * docs suggest that one should disable NMI while + * reading/writing CMOS data, and enable it again + * afterwards. This would yield the sequence + * + * outb (reg | 0x80, 0x70); + * val = inb(0x71); + * outb (0x0d, 0x70); // 0x0d: random read-only location + * + * Other docs state that "any write to 0x70 should be + * followed by an action to 0x71 or the RTC wil be left in + * an unknown state". Most docs say that it doesnt matter at + * all what one does. + */ + /* + * bit 0x80: disable NMI while reading - should we? Let us + * follow the kernel and not disable. Called only with 0 <= + * reg < 128 + */ + outb(reg, clock_ctl_addr); + return inb(clock_data_addr); + } } -static inline -unsigned long cmos_write(unsigned long reg, unsigned long val) +static inline unsigned long cmos_write(unsigned long reg, unsigned long val) { - if (use_dev_port) { - unsigned char v = reg | 0x80; - lseek(dev_port_fd, clock_ctl_addr, 0); - if (write(dev_port_fd, &v, 1) == -1 && debug) - printf(_("cmos_write(): write to control address %X failed: %s\n"), clock_ctl_addr, strerror(errno)); - v = (val & 0xff); - lseek(dev_port_fd, clock_data_addr, 0); - if (write(dev_port_fd, &v, 1) == -1 && debug) - printf(_("cmos_write(): write to data address %X failed: %s\n"), clock_data_addr, strerror(errno)); - } else { - outb (reg, clock_ctl_addr); - outb (val, clock_data_addr); - } - return 0; + if (use_dev_port) { + unsigned char v = reg | 0x80; + lseek(dev_port_fd, clock_ctl_addr, 0); + if (write(dev_port_fd, &v, 1) == -1 && debug) + printf(_ + ("cmos_write(): write to control address %X failed: %s\n"), + clock_ctl_addr, strerror(errno)); + v = (val & 0xff); + lseek(dev_port_fd, clock_data_addr, 0); + if (write(dev_port_fd, &v, 1) == -1 && debug) + printf(_ + ("cmos_write(): write to data address %X failed: %s\n"), + clock_data_addr, strerror(errno)); + } else { + outb(reg, clock_ctl_addr); + outb(val, clock_data_addr); + } + return 0; } static unsigned long cmos_set_time(unsigned long arg) { - unsigned char save_control, save_freq_select, pmbit = 0; - struct tm tm = *(struct tm *) arg; - unsigned int century; + unsigned char save_control, save_freq_select, pmbit = 0; + struct tm tm = *(struct tm *)arg; + unsigned int century; /* * CMOS byte 10 (clock status register A) has 3 bitfields: @@ -349,260 +389,261 @@ static unsigned long cmos_set_time(unsigned long arg) * 1111 500 milliseconds (maximum, 2 Hz) * 0110 976.562 microseconds (default 1024 Hz) */ + save_control = cmos_read(11); /* tell the clock it's being set */ + cmos_write(11, (save_control | 0x80)); + save_freq_select = cmos_read(10); /* stop and reset prescaler */ + cmos_write(10, (save_freq_select | 0x70)); - save_control = cmos_read (11); /* tell the clock it's being set */ - cmos_write (11, (save_control | 0x80)); - save_freq_select = cmos_read (10); /* stop and reset prescaler */ - cmos_write (10, (save_freq_select | 0x70)); + tm.tm_year += TM_EPOCH; + century = tm.tm_year / 100; + tm.tm_year -= cmos_epoch; + tm.tm_year %= 100; + tm.tm_mon += 1; + tm.tm_wday += 1; - tm.tm_year += TM_EPOCH; - century = tm.tm_year/100; - tm.tm_year -= cmos_epoch; - tm.tm_year %= 100; - tm.tm_mon += 1; - tm.tm_wday += 1; + if (!(save_control & 0x02)) { /* 12hr mode; the default is 24hr mode */ + if (tm.tm_hour == 0) + tm.tm_hour = 24; + if (tm.tm_hour > 12) { + tm.tm_hour -= 12; + pmbit = 0x80; + } + } - if (!(save_control & 0x02)) { /* 12hr mode; the default is 24hr mode */ - if (tm.tm_hour == 0) - tm.tm_hour = 24; - if (tm.tm_hour > 12) { - tm.tm_hour -= 12; - pmbit = 0x80; - } - } + if (!(save_control & 0x04)) { /* BCD mode - the default */ + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_wday); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_year); + BIN_TO_BCD(century); + } - if (!(save_control & 0x04)) { /* BCD mode - the default */ - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_wday); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_year); - BIN_TO_BCD(century); - } + cmos_write(0, tm.tm_sec); + cmos_write(2, tm.tm_min); + cmos_write(4, tm.tm_hour | pmbit); + cmos_write(6, tm.tm_wday); + cmos_write(7, tm.tm_mday); + cmos_write(8, tm.tm_mon); + cmos_write(9, tm.tm_year); + if (century_byte) + cmos_write(century_byte, century); - cmos_write (0, tm.tm_sec); - cmos_write (2, tm.tm_min); - cmos_write (4, tm.tm_hour | pmbit); - cmos_write (6, tm.tm_wday); - cmos_write (7, tm.tm_mday); - cmos_write (8, tm.tm_mon); - cmos_write (9, tm.tm_year); - if (century_byte) - cmos_write (century_byte, century); - - - /* The kernel sources, linux/arch/i386/kernel/time.c, have the - following comment: - - The following flags have to be released exactly in this order, - otherwise the DS12887 (popular MC146818A clone with integrated - battery and quartz) will not reset the oscillator and will not - update precisely 500 ms later. You won't find this mentioned - in the Dallas Semiconductor data sheets, but who believes data - sheets anyway ... -- Markus Kuhn - */ - - cmos_write (11, save_control); - cmos_write (10, save_freq_select); - return 0; + /* + * The kernel sources, linux/arch/i386/kernel/time.c, have the + * following comment: + * + * The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + cmos_write(11, save_control); + cmos_write(10, save_freq_select); + return 0; } -static int -hclock_read(unsigned long reg) { +static int hclock_read(unsigned long reg) +{ return atomic("clock read", cmos_read, (reg)); } -static void -hclock_set_time(const struct tm *tm) { +static void hclock_set_time(const struct tm *tm) +{ atomic("set time", cmos_set_time, (unsigned long)(tm)); } -static inline int -cmos_clock_busy(void) { +static inline int cmos_clock_busy(void) +{ return #ifdef __alpha__ - /* poll bit 4 (UF) of Control Register C */ + /* poll bit 4 (UF) of Control Register C */ funkyTOY ? (hclock_read(12) & 0x10) : #endif - /* poll bit 7 (UIP) of Control Register A */ + /* poll bit 7 (UIP) of Control Register A */ (hclock_read(10) & 0x80); } +static int synchronize_to_clock_tick_cmos(void) +{ + int i; -static int -synchronize_to_clock_tick_cmos(void) { - int i; + /* + * Wait for rise. Should be within a second, but in case something + * weird happens, we have a limit on this loop to reduce the impact + * of this failure. + */ + for (i = 0; !cmos_clock_busy(); i++) + if (i >= 10000000) + return 1; - /* Wait for rise. Should be within a second, but in case something - weird happens, we have a limit on this loop to reduce the impact - of this failure. - */ - for (i = 0; !cmos_clock_busy(); i++) - if (i >= 10000000) - return 1; - - /* Wait for fall. Should be within 2.228 ms. */ - for (i = 0; cmos_clock_busy(); i++) - if (i >= 1000000) - return 1; - return 0; + /* Wait for fall. Should be within 2.228 ms. */ + for (i = 0; cmos_clock_busy(); i++) + if (i >= 1000000) + return 1; + return 0; } +/* + * Read the hardware clock and return the current time via argument. + * Assume we have an ISA machine and read the clock directly with CPU I/O + * instructions. + * + * This function is not totally reliable. It takes a finite and + * unpredictable amount of time to execute the code below. During that time, + * the clock may change and we may even read an invalid value in the middle + * of an update. We do a few checks to minimize this possibility, but only + * the kernel can actually read the clock properly, since it can execute + * code in a short and predictable amount of time (by turning of + * interrupts). + * + * In practice, the chance of this function returning the wrong time is + * extremely remote. + */ +static int read_hardware_clock_cmos(struct tm *tm) +{ + bool got_time = FALSE; + unsigned char status, pmbit; + status = pmbit = 0; /* just for gcc */ -static int -read_hardware_clock_cmos(struct tm *tm) { -/*---------------------------------------------------------------------------- - Read the hardware clock and return the current time via argument. - Assume we have an ISA machine and read the clock directly with CPU I/O - instructions. - - This function is not totally reliable. It takes a finite and - unpredictable amount of time to execute the code below. During that - time, the clock may change and we may even read an invalid value in - the middle of an update. We do a few checks to minimize this - possibility, but only the kernel can actually read the clock - properly, since it can execute code in a short and predictable - amount of time (by turning of interrupts). - - In practice, the chance of this function returning the wrong time is - extremely remote. - ------------------------------------------------------------------------------*/ - bool got_time = FALSE; - unsigned char status, pmbit; - - status = pmbit = 0; /* just for gcc */ - - while (!got_time) { - /* Bit 7 of Byte 10 of the Hardware Clock value is the Update In Progress - (UIP) bit, which is on while and 244 uS before the Hardware Clock - updates itself. It updates the counters individually, so reading - them during an update would produce garbage. The update takes 2mS, - so we could be spinning here that long waiting for this bit to turn - off. - - Furthermore, it is pathologically possible for us to be in this - code so long that even if the UIP bit is not on at first, the - clock has changed while we were running. We check for that too, - and if it happens, we start over. - */ - - if (!cmos_clock_busy()) { - /* No clock update in progress, go ahead and read */ - tm->tm_sec = hclock_read(0); - tm->tm_min = hclock_read(2); - tm->tm_hour = hclock_read(4); - tm->tm_wday = hclock_read(6); - tm->tm_mday = hclock_read(7); - tm->tm_mon = hclock_read(8); - tm->tm_year = hclock_read(9); - status = hclock_read(11); + while (!got_time) { + /* + * Bit 7 of Byte 10 of the Hardware Clock value is the + * Update In Progress (UIP) bit, which is on while and 244 + * uS before the Hardware Clock updates itself. It updates + * the counters individually, so reading them during an + * update would produce garbage. The update takes 2mS, so we + * could be spinning here that long waiting for this bit to + * turn off. + * + * Furthermore, it is pathologically possible for us to be + * in this code so long that even if the UIP bit is not on + * at first, the clock has changed while we were running. We + * check for that too, and if it happens, we start over. + */ + if (!cmos_clock_busy()) { + /* No clock update in progress, go ahead and read */ + tm->tm_sec = hclock_read(0); + tm->tm_min = hclock_read(2); + tm->tm_hour = hclock_read(4); + tm->tm_wday = hclock_read(6); + tm->tm_mday = hclock_read(7); + tm->tm_mon = hclock_read(8); + tm->tm_year = hclock_read(9); + status = hclock_read(11); #if 0 - if (century_byte) - century = hclock_read(century_byte); + if (century_byte) + century = hclock_read(century_byte); #endif + /* + * Unless the clock changed while we were reading, + * consider this a good clock read . + */ + if (tm->tm_sec == hclock_read(0)) + got_time = TRUE; + } + /* + * Yes, in theory we could have been running for 60 seconds + * and the above test wouldn't work! + */ + } - /* Unless the clock changed while we were reading, consider this - a good clock read . - */ - if (tm->tm_sec == hclock_read (0)) - got_time = TRUE; - } - /* Yes, in theory we could have been running for 60 seconds and - the above test wouldn't work! - */ - } - - if (!(status & 0x04)) { /* BCD mode - the default */ - BCD_TO_BIN(tm->tm_sec); - BCD_TO_BIN(tm->tm_min); - pmbit = (tm->tm_hour & 0x80); - tm->tm_hour &= 0x7f; - BCD_TO_BIN(tm->tm_hour); - BCD_TO_BIN(tm->tm_wday); - BCD_TO_BIN(tm->tm_mday); - BCD_TO_BIN(tm->tm_mon); - BCD_TO_BIN(tm->tm_year); + if (!(status & 0x04)) { /* BCD mode - the default */ + BCD_TO_BIN(tm->tm_sec); + BCD_TO_BIN(tm->tm_min); + pmbit = (tm->tm_hour & 0x80); + tm->tm_hour &= 0x7f; + BCD_TO_BIN(tm->tm_hour); + BCD_TO_BIN(tm->tm_wday); + BCD_TO_BIN(tm->tm_mday); + BCD_TO_BIN(tm->tm_mon); + BCD_TO_BIN(tm->tm_year); #if 0 - BCD_TO_BIN(century); + BCD_TO_BIN(century); #endif - } + } - /* We don't use the century byte of the Hardware Clock - since we don't know its address (usually 50 or 55). - Here, we follow the advice of the X/Open Base Working Group: - "if century is not specified, then values in the range [69-99] - refer to years in the twentieth century (1969 to 1999 inclusive), - and values in the range [00-68] refer to years in the twenty-first - century (2000 to 2068 inclusive)." - */ + /* + * We don't use the century byte of the Hardware Clock since we + * don't know its address (usually 50 or 55). Here, we follow the + * advice of the X/Open Base Working Group: "if century is not + * specified, then values in the range [69-99] refer to years in the + * twentieth century (1969 to 1999 inclusive), and values in the + * range [00-68] refer to years in the twenty-first century (2000 to + * 2068 inclusive)." + */ + tm->tm_wday -= 1; + tm->tm_mon -= 1; + tm->tm_year += (cmos_epoch - TM_EPOCH); + if (tm->tm_year < 69) + tm->tm_year += 100; + if (pmbit) { + tm->tm_hour += 12; + if (tm->tm_hour == 24) + tm->tm_hour = 0; + } - tm->tm_wday -= 1; - tm->tm_mon -= 1; - tm->tm_year += (cmos_epoch - TM_EPOCH); - if (tm->tm_year < 69) - tm->tm_year += 100; - if (pmbit) { - tm->tm_hour += 12; - if (tm->tm_hour == 24) - tm->tm_hour = 0; - } - - tm->tm_isdst = -1; /* don't know whether it's daylight */ - return 0; + tm->tm_isdst = -1; /* don't know whether it's daylight */ + return 0; } +static int set_hardware_clock_cmos(const struct tm *new_broken_time) +{ - -static int -set_hardware_clock_cmos(const struct tm *new_broken_time) { - - hclock_set_time(new_broken_time); - return 0; + hclock_set_time(new_broken_time); + return 0; } -static int -i386_iopl(const int level) { +static int i386_iopl(const int level) +{ #if defined(__i386__) || defined(__alpha__) #if defined(HAVE_IOPL) - extern int iopl(const int lvl); - return iopl(level); + extern int iopl(const int lvl); + return iopl(level); #else - extern int ioperm(unsigned long from, unsigned long num, int turn_on); - return ioperm(clock_ctl_addr, 2, 1); + extern int ioperm(unsigned long from, unsigned long num, int turn_on); + return ioperm(clock_ctl_addr, 2, 1); #endif #else - return -2; + return -2; #endif } -static int -get_permissions_cmos(void) { - int rc; +static int get_permissions_cmos(void) +{ + int rc; - if (use_dev_port) { - if ((dev_port_fd = open("/dev/port", O_RDWR)) < 0) { - int errsv = errno; - fprintf(stderr, _("Cannot open /dev/port: %s"), strerror(errsv)); - rc = 1; - } else - rc = 0; - } else { - rc = i386_iopl(3); - if (rc == -2) { - fprintf(stderr, _("I failed to get permission because I didn't try.\n")); - } else if (rc != 0) { - rc = errno; - fprintf(stderr, _("%s is unable to get I/O port access: " - "the iopl(3) call failed.\n"), progname); - if(rc == EPERM && geteuid()) - fprintf(stderr, _("Probably you need root privileges.\n")); - } - } - return rc ? 1 : 0; + if (use_dev_port) { + if ((dev_port_fd = open("/dev/port", O_RDWR)) < 0) { + int errsv = errno; + fprintf(stderr, _("Cannot open /dev/port: %s"), + strerror(errsv)); + rc = 1; + } else + rc = 0; + } else { + rc = i386_iopl(3); + if (rc == -2) { + fprintf(stderr, + _ + ("I failed to get permission because I didn't try.\n")); + } else if (rc != 0) { + rc = errno; + fprintf(stderr, + _("%s is unable to get I/O port access: " + "the iopl(3) call failed.\n"), progname); + if (rc == EPERM && geteuid()) + fprintf(stderr, + _ + ("Probably you need root privileges.\n")); + } + } + return rc ? 1 : 0; } static struct clock_ops cmos = { @@ -613,17 +654,17 @@ static struct clock_ops cmos = { synchronize_to_clock_tick_cmos, }; - -/* return &cmos if cmos clock present, NULL otherwise */ -/* choose this construction to avoid gcc messages about unused variables */ - -struct clock_ops * -probe_for_cmos_clock(void){ - int have_cmos = +/* + * return &cmos if cmos clock present, NULL otherwise choose this + * construction to avoid gcc messages about unused variables + */ +struct clock_ops *probe_for_cmos_clock(void) +{ + int have_cmos = #if defined(__i386__) || defined(__alpha__) TRUE; #else FALSE; #endif - return have_cmos ? &cmos : NULL; + return have_cmos ? &cmos : NULL; } diff --git a/hwclock/hwclock.c b/hwclock/hwclock.c index 68e76b896..0c6b0f6cd 100644 --- a/hwclock/hwclock.c +++ b/hwclock/hwclock.c @@ -8,35 +8,24 @@ * * Major rewrite by Bryan Henderson , 96.09.19. * The new program is called hwclock. New features: - * - You can set the hardware clock without also modifying the system clock. - * - You can read and set the clock with finer than 1 second precision. - * - When you set the clock, hwclock automatically refigures the drift - * rate, based on how far off the clock was before you set it. + * + * - You can set the hardware clock without also modifying the system + * clock. + * - You can read and set the clock with finer than 1 second precision. + * - When you set the clock, hwclock automatically refigures the drift + * rate, based on how far off the clock was before you set it. * * Reshuffled things, added sparc code, and re-added alpha stuff * by David Mosberger * and Jay Estabrook * and Martin Ostermann , aeb@cwi.nl, 990212. * - * Fix for Award 2094 bug, Dave Coffin (dcoffin@shore.net) 11/12/98 + * Fix for Award 2094 bug, Dave Coffin (dcoffin@shore.net) 11/12/98 * Change of local time handling, Stefan Ring * Change of adjtime handling, James P. Rutledge . * * Distributed under GPL */ - -/* - * clock [-u] -r - read hardware clock - * clock [-u] -w - write hardware clock from system time - * clock [-u] -s - set system time from hardware clock - * clock [-u] -a - set system time from hardware clock, adjust the time - * to correct for systematic error, and write it back to - * the hardware clock - * -u indicates cmos clock is kept in universal time - * -A indicates cmos clock is kept in Alpha ARC console time (0 == 1980) - * -J indicates we're dealing with a Jensen (early DEC Alpha PC) - */ - /* * Explanation of `adjusting' (Rob Hooft): * @@ -49,23 +38,23 @@ * to determine the correction, and to save its data. In this file are * three numbers: * - * 1) the correction in seconds per day. (So if your clock runs 5 - * seconds per day fast, the first number should read -5.0) - * 2) the number of seconds since 1/1/1970 the last time the program - * was used - * 3) the remaining part of a second which was leftover after the last - * adjustment + * 1) the correction in seconds per day. (So if your clock runs 5 + * seconds per day fast, the first number should read -5.0) + * 2) the number of seconds since 1/1/1970 the last time the program + * was used + * 3) the remaining part of a second which was leftover after the last + * adjustment * * Installation and use of this program: * - * a) create a file '/etc/adjtime' containing as the first and only line: - * '0.0 0 0.0' - * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in - * universal or local time. This updates the second number. - * c) set your system time using the 'date' command. - * d) update your cmos time using 'clock -wu' or 'clock -w' - * e) replace the first number in /etc/adjtime by your correction. - * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local' + * a) create a file '/etc/adjtime' containing as the first and only + * line: '0.0 0 0.0' + * b) run 'clock -au' or 'clock -a', depending on whether your cmos is + * in universal or local time. This updates the second number. + * c) set your system time using the 'date' command. + * d) update your cmos time using 'clock -wu' or 'clock -w' + * e) replace the first number in /etc/adjtime by your correction. + * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local' */ #include @@ -108,115 +97,125 @@ const char *adj_file_name = NULL; #define LASTDATE "/var/lib/lastdate" struct adjtime { - /* This is information we keep in the adjtime file that tells us how - to do drift corrections. Elements are all straight from the - adjtime file, so see documentation of that file for details. - Exception is , which is an indication that what's in this - structure is not what's in the disk file (because it has been - updated since read from the disk file). - */ - bool dirty; - - /* line 1 */ - double drift_factor; - time_t last_adj_time; - double not_adjusted; - - /* line 2 */ - time_t last_calib_time; - /* The most recent time that we set the clock from an external - authority (as opposed to just doing a drift adjustment) */ - - /* line 3 */ - enum a_local_utc {LOCAL, UTC, UNKNOWN} local_utc; - /* To which time zone, local or UTC, we most recently set the - hardware clock. */ + /* + * This is information we keep in the adjtime file that tells us how + * to do drift corrections. Elements are all straight from the + * adjtime file, so see documentation of that file for details. + * Exception is , which is an indication that what's in this + * structure is not what's in the disk file (because it has been + * updated since read from the disk file). + */ + bool dirty; + /* line 1 */ + double drift_factor; + time_t last_adj_time; + double not_adjusted; + /* line 2 */ + time_t last_calib_time; + /* + * The most recent time that we set the clock from an external + * authority (as opposed to just doing a drift adjustment) + */ + /* line 3 */ + enum a_local_utc { LOCAL, UTC, UNKNOWN } local_utc; + /* + * To which time zone, local or UTC, we most recently set the + * hardware clock. + */ }; -bool debug; - /* We are running in debug mode, wherein we put a lot of information about - what we're doing to standard output. */ - -bool badyear; - /* Workaround for Award 4.50g BIOS bug: keep the year in a file. */ - -int epoch_option = -1; - /* User-specified epoch, used when rtc fails to return epoch. */ /* - * Almost all Award BIOS's made between 04/26/94 and 05/31/95 - * have a nasty bug limiting the RTC year byte to the range 94-99. - * Any year between 2000 and 2093 gets changed to 2094, every time - * you start the system. - * With the --badyear option, we write the date to file and hope - * that the file is updated at least once a year. - * I recommend putting this command "hwclock --badyear" in the monthly - * crontab, just to be safe. -- Dave Coffin 11/12/98 + * We are running in debug mode, wherein we put a lot of information about + * what we're doing to standard output. */ -static void -write_date_to_file (struct tm *tm) { - FILE *fp; +bool debug; - if ((fp = fopen(LASTDATE,"w"))) { - fprintf(fp,"%02d.%02d.%04d\n", tm->tm_mday, tm->tm_mon+1, - tm->tm_year+1900); - fclose(fp); - } else - perror(LASTDATE); +/* Workaround for Award 4.50g BIOS bug: keep the year in a file. */ +bool badyear; + +/* User-specified epoch, used when rtc fails to return epoch. */ +int epoch_option = -1; + +/* + * Almost all Award BIOS's made between 04/26/94 and 05/31/95 have a nasty + * bug limiting the RTC year byte to the range 94-99. Any year between 2000 + * and 2093 gets changed to 2094, every time you start the system. + * + * With the --badyear option, we write the date to file and hope that the + * file is updated at least once a year. I recommend putting this command + * "hwclock --badyear" in the monthly crontab, just to be safe. + * + * -- Dave Coffin 11/12/98 + */ +static void write_date_to_file(struct tm *tm) +{ + FILE *fp; + + if ((fp = fopen(LASTDATE, "w"))) { + fprintf(fp, "%02d.%02d.%04d\n", tm->tm_mday, tm->tm_mon + 1, + tm->tm_year + 1900); + fclose(fp); + } else + perror(LASTDATE); } -static void -read_date_from_file (struct tm *tm) { - int last_mday, last_mon, last_year; - FILE *fp; +static void read_date_from_file(struct tm *tm) +{ + int last_mday, last_mon, last_year; + FILE *fp; - if ((fp = fopen(LASTDATE,"r"))) { - if (fscanf (fp,"%d.%d.%d\n", &last_mday, &last_mon, &last_year) == 3) { - tm->tm_year = last_year-1900; - if ((tm->tm_mon << 5) + tm->tm_mday < ((last_mon-1) << 5) + last_mday) - tm->tm_year ++; - } - fclose(fp); - } - write_date_to_file (tm); + if ((fp = fopen(LASTDATE, "r"))) { + if (fscanf(fp, "%d.%d.%d\n", &last_mday, &last_mon, &last_year) + == 3) { + tm->tm_year = last_year - 1900; + if ((tm->tm_mon << 5) + tm->tm_mday < + ((last_mon - 1) << 5) + last_mday) + tm->tm_year++; + } + fclose(fp); + } + write_date_to_file(tm); } -double -time_diff(struct timeval subtrahend, struct timeval subtractor) { -/*--------------------------------------------------------------------------- - The difference in seconds between two times in "timeval" format. -----------------------------------------------------------------------------*/ - return (subtrahend.tv_sec - subtractor.tv_sec) - + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6; +/* + * The difference in seconds between two times in "timeval" format. + */ +double time_diff(struct timeval subtrahend, struct timeval subtractor) +{ + return (subtrahend.tv_sec - subtractor.tv_sec) + + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6; } +/* + * The time, in "timeval" format, which is seconds after the + * time . Of course, may be negative. + */ +static struct timeval time_inc(struct timeval addend, double increment) +{ + struct timeval newtime; -static struct timeval -time_inc(struct timeval addend, double increment) { -/*---------------------------------------------------------------------------- - The time, in "timeval" format, which is seconds after - the time . Of course, may be negative. ------------------------------------------------------------------------------*/ - struct timeval newtime; + newtime.tv_sec = addend.tv_sec + (int)increment; + newtime.tv_usec = addend.tv_usec + (increment - (int)increment) * 1E6; - newtime.tv_sec = addend.tv_sec + (int) increment; - newtime.tv_usec = addend.tv_usec + (increment - (int) increment) * 1E6; - - /* Now adjust it so that the microsecond value is between 0 and 1 million */ - if (newtime.tv_usec < 0) { - newtime.tv_usec += 1E6; - newtime.tv_sec -= 1; - } else if (newtime.tv_usec >= 1E6) { - newtime.tv_usec -= 1E6; - newtime.tv_sec += 1; - } - return newtime; + /* + * Now adjust it so that the microsecond value is between 0 and 1 + * million. + */ + if (newtime.tv_usec < 0) { + newtime.tv_usec += 1E6; + newtime.tv_sec -= 1; + } else if (newtime.tv_usec >= 1E6) { + newtime.tv_usec -= 1E6; + newtime.tv_sec += 1; + } + return newtime; } - static bool hw_clock_is_utc(const bool utc, const bool local_opt, - const struct adjtime adjtime) { + const struct adjtime adjtime) +{ bool ret; if (utc) @@ -224,7 +223,7 @@ hw_clock_is_utc(const bool utc, const bool local_opt, else if (local_opt) ret = FALSE; /* --localtime explicitly given */ else - /* get info from adjtime file - default is UTC */ + /* get info from adjtime file - default is UTC */ ret = (adjtime.local_utc != LOCAL); if (debug) printf(_("Assuming hardware clock is kept in %s time.\n"), @@ -232,122 +231,120 @@ hw_clock_is_utc(const bool utc, const bool local_opt, return ret; } +/* + * Read the adjustment parameters out of the /etc/adjtime file. + * + * Return them as the adjtime structure <*adjtime_p>. If there is no + * /etc/adjtime file, return defaults. If values are missing from the file, + * return defaults for them. + * + * return value 0 if all OK, !=0 otherwise. + */ +static int read_adjtime(struct adjtime *adjtime_p) +{ + FILE *adjfile; + int rc; /* local return code */ + struct stat statbuf; /* We don't even use the contents of this. */ + char line1[81]; /* String: first line of adjtime file */ + char line2[81]; /* String: second line of adjtime file */ + char line3[81]; /* String: third line of adjtime file */ + long timeval; + rc = stat(adj_file_name, &statbuf); + if (rc < 0 && errno == ENOENT) { + /* He doesn't have a adjtime file, so we'll use defaults. */ + adjtime_p->drift_factor = 0; + adjtime_p->last_adj_time = 0; + adjtime_p->not_adjusted = 0; + adjtime_p->last_calib_time = 0; + adjtime_p->local_utc = UNKNOWN; + adjtime_p->dirty = FALSE; /* don't create a zero adjfile */ -static int -read_adjtime(struct adjtime *adjtime_p) { -/*---------------------------------------------------------------------------- - Read the adjustment parameters out of the /etc/adjtime file. - - Return them as the adjtime structure <*adjtime_p>. - If there is no /etc/adjtime file, return defaults. - If values are missing from the file, return defaults for them. - - return value 0 if all OK, !=0 otherwise. - ------------------------------------------------------------------------------*/ - FILE *adjfile; - int rc; /* local return code */ - struct stat statbuf; /* We don't even use the contents of this. */ - - rc = stat(adj_file_name, &statbuf); - if (rc < 0 && errno == ENOENT) { - /* He doesn't have a adjtime file, so we'll use defaults. */ - adjtime_p->drift_factor = 0; - adjtime_p->last_adj_time = 0; - adjtime_p->not_adjusted = 0; - adjtime_p->last_calib_time = 0; - adjtime_p->local_utc = UNKNOWN; - adjtime_p->dirty = FALSE; /* don't create a zero adjfile */ - - return 0; - } - - adjfile = fopen(adj_file_name, "r"); /* open file for reading */ - if (adjfile == NULL) { - outsyserr("cannot open file %s", adj_file_name); - return EX_OSFILE; - } - - { - char line1[81]; /* String: first line of adjtime file */ - char line2[81]; /* String: second line of adjtime file */ - char line3[81]; /* String: third line of adjtime file */ - long timeval; - - if (!fgets(line1, sizeof(line1), adjfile)) - line1[0] = '\0'; /* In case fgets fails */ - if (!fgets(line2, sizeof(line2), adjfile)) - line2[0] = '\0'; /* In case fgets fails */ - if (!fgets(line3, sizeof(line3), adjfile)) - line3[0] = '\0'; /* In case fgets fails */ - - fclose(adjfile); - - /* Set defaults in case values are missing from file */ - adjtime_p->drift_factor = 0; - adjtime_p->last_adj_time = 0; - adjtime_p->not_adjusted = 0; - adjtime_p->last_calib_time = 0; - timeval = 0; - - sscanf(line1, "%lf %ld %lf", - &adjtime_p->drift_factor, - &timeval, - &adjtime_p->not_adjusted); - adjtime_p->last_adj_time = timeval; - - sscanf(line2, "%ld", &timeval); - adjtime_p->last_calib_time = timeval; - - if (!strcmp(line3, "UTC\n")) - adjtime_p->local_utc = UTC; - else if (!strcmp(line3, "LOCAL\n")) - adjtime_p->local_utc = LOCAL; - else { - adjtime_p->local_utc = UNKNOWN; - if (line3[0]) { - fprintf(stderr, - _("%s: Warning: unrecognized third line in adjtime file\n"), - MYNAME); - fprintf(stderr, _("(Expected: `UTC' or `LOCAL' or nothing.)\n")); + return 0; } - } - } - adjtime_p->dirty = FALSE; - if (debug) { - printf(_("Last drift adjustment done at %ld seconds after 1969\n"), - (long) adjtime_p->last_adj_time); - printf(_("Last calibration done at %ld seconds after 1969\n"), - (long) adjtime_p->last_calib_time); - printf(_("Hardware clock is on %s time\n"), - (adjtime_p->local_utc == LOCAL) ? _("local") : - (adjtime_p->local_utc == UTC) ? _("UTC") : _("unknown")); - } + adjfile = fopen(adj_file_name, "r"); /* open file for reading */ + if (adjfile == NULL) { + outsyserr("cannot open file %s", adj_file_name); + return EX_OSFILE; + } - return 0; + + if (!fgets(line1, sizeof(line1), adjfile)) + line1[0] = '\0'; /* In case fgets fails */ + if (!fgets(line2, sizeof(line2), adjfile)) + line2[0] = '\0'; /* In case fgets fails */ + if (!fgets(line3, sizeof(line3), adjfile)) + line3[0] = '\0'; /* In case fgets fails */ + + fclose(adjfile); + + /* Set defaults in case values are missing from file */ + adjtime_p->drift_factor = 0; + adjtime_p->last_adj_time = 0; + adjtime_p->not_adjusted = 0; + adjtime_p->last_calib_time = 0; + timeval = 0; + + sscanf(line1, "%lf %ld %lf", + &adjtime_p->drift_factor, + &timeval, &adjtime_p->not_adjusted); + adjtime_p->last_adj_time = timeval; + + sscanf(line2, "%ld", &timeval); + adjtime_p->last_calib_time = timeval; + + if (!strcmp(line3, "UTC\n")) { + adjtime_p->local_utc = UTC; + } else if (!strcmp(line3, "LOCAL\n")) { + adjtime_p->local_utc = LOCAL; + } else { + adjtime_p->local_utc = UNKNOWN; + if (line3[0]) { + fprintf(stderr, + _("%s: Warning: unrecognized third line in adjtime file\n"), + MYNAME); + fprintf(stderr, + _("(Expected: `UTC' or `LOCAL' or nothing.)\n")); + } + } + + adjtime_p->dirty = FALSE; + + if (debug) { + printf(_ + ("Last drift adjustment done at %ld seconds after 1969\n"), + (long)adjtime_p->last_adj_time); + printf(_("Last calibration done at %ld seconds after 1969\n"), + (long)adjtime_p->last_calib_time); + printf(_("Hardware clock is on %s time\n"), + (adjtime_p->local_utc == + LOCAL) ? _("local") : (adjtime_p->local_utc == + UTC) ? _("UTC") : _("unknown")); + } + + return 0; } - -static int -synchronize_to_clock_tick(void) { -/*----------------------------------------------------------------------------- - Wait until the falling edge of the Hardware Clock's update flag so - that any time that is read from the clock immediately after we - return will be exact. - - The clock only has 1 second precision, so it gives the exact time only - once per second, right on the falling edge of the update flag. - - We wait (up to one second) either blocked waiting for an rtc device - or in a CPU spin loop. The former is probably not very accurate. - - Return 0 if it worked, nonzero if it didn't. ------------------------------------------------------------------------------*/ +/* + * Wait until the falling edge of the Hardware Clock's update flag so that + * any time that is read from the clock immediately after we return will be + * exact. + * + * The clock only has 1 second precision, so it gives the exact time only + * once per second, right on the falling edge of the update flag. + * + * We wait (up to one second) either blocked waiting for an rtc device or in + * a CPU spin loop. The former is probably not very accurate. + * + * Return 0 if it worked, nonzero if it didn't. + */ +static int synchronize_to_clock_tick(void) +{ int rc; - if (debug) printf(_("Waiting for clock tick...\n")); + if (debug) + printf(_("Waiting for clock tick...\n")); rc = ur->synchronize_to_clock_tick(); @@ -361,254 +358,259 @@ synchronize_to_clock_tick(void) { return rc; } - - +/* + * Convert a time in broken down format (hours, minutes, etc.) into standard + * unix time (seconds into epoch). Return it as *systime_p. + * + * The broken down time is argument . This broken down time is either + * in local time zone or UTC, depending on value of logical argument + * "universal". True means it is in UTC. + * + * If the argument contains values that do not constitute a valid time, and + * mktime() recognizes this, return *valid_p == false and *systime_p + * undefined. However, mktime() sometimes goes ahead and computes a + * fictional time "as if" the input values were valid, e.g. if they indicate + * the 31st day of April, mktime() may compute the time of May 1. In such a + * case, we return the same fictional value mktime() does as *systime_p and + * return *valid_p == true. + */ static void mktime_tz(struct tm tm, const bool universal, - bool *valid_p, time_t *systime_p) { -/*----------------------------------------------------------------------------- - Convert a time in broken down format (hours, minutes, etc.) into standard - unix time (seconds into epoch). Return it as *systime_p. + bool * valid_p, time_t * systime_p) +{ + time_t mktime_result; /* The value returned by our mktime() call */ + char *zone; /* Local time zone name */ - The broken down time is argument . This broken down time is either in - local time zone or UTC, depending on value of logical argument "universal". - True means it is in UTC. - - If the argument contains values that do not constitute a valid time, - and mktime() recognizes this, return *valid_p == false and - *systime_p undefined. However, mktime() sometimes goes ahead and - computes a fictional time "as if" the input values were valid, - e.g. if they indicate the 31st day of April, mktime() may compute - the time of May 1. In such a case, we return the same fictional - value mktime() does as *systime_p and return *valid_p == true. - ------------------------------------------------------------------------------*/ - time_t mktime_result; /* The value returned by our mktime() call */ - char *zone; /* Local time zone name */ - - /* We use the C library function mktime(), but since it only works on - local time zone input, we may have to fake it out by temporarily - changing the local time zone to UTC. - */ - zone = getenv("TZ"); /* remember original time zone */ - if (universal) { - /* Set timezone to UTC */ - setenv("TZ", "", TRUE); - /* Note: tzset() gets called implicitly by the time code, but only the - first time. When changing the environment variable, better call - tzset() explicitly. - */ - tzset(); - } - mktime_result = mktime(&tm); - if (mktime_result == -1) { - /* This apparently (not specified in mktime() documentation) means - the 'tm' structure does not contain valid values (however, not - containing valid values does _not_ imply mktime() returns -1). - */ - *valid_p = FALSE; - *systime_p = 0; - if (debug) - printf(_("Invalid values in hardware clock: " - "%4d/%.2d/%.2d %.2d:%.2d:%.2d\n"), - tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - } else { - *valid_p = TRUE; - *systime_p = mktime_result; - if (debug) - printf(_("Hw clock time : %4d/%.2d/%.2d %.2d:%.2d:%.2d = " - "%ld seconds since 1969\n"), - tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, (long) *systime_p); - } - /* now put back the original zone. */ - if (zone) setenv("TZ", zone, TRUE); - else unsetenv("TZ"); - tzset(); + /* + * We use the C library function mktime(), but since it only works + * on local time zone input, we may have to fake it out by + * temporarily changing the local time zone to UTC. + */ + zone = getenv("TZ"); /* remember original time zone */ + if (universal) { + /* Set timezone to UTC */ + setenv("TZ", "", TRUE); + /* + * Note: tzset() gets called implicitly by the time code, + * but only the first time. When changing the environment + * variable, better call tzset() explicitly. + */ + tzset(); + } + mktime_result = mktime(&tm); + if (mktime_result == -1) { + /* + * This apparently (not specified in mktime() documentation) + * means the 'tm' structure does not contain valid values + * (however, not containing valid values does _not_ imply + * mktime() returns -1). + */ + *valid_p = FALSE; + *systime_p = 0; + if (debug) + printf(_("Invalid values in hardware clock: " + "%4d/%.2d/%.2d %.2d:%.2d:%.2d\n"), + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + } else { + *valid_p = TRUE; + *systime_p = mktime_result; + if (debug) + printf(_ + ("Hw clock time : %4d/%.2d/%.2d %.2d:%.2d:%.2d = " + "%ld seconds since 1969\n"), tm.tm_year + 1900, + tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec, (long)*systime_p); + } + /* now put back the original zone. */ + if (zone) + setenv("TZ", zone, TRUE); + else + unsetenv("TZ"); + tzset(); } - +/* + * Read the hardware clock and return the current time via argument. + * + * Use the method indicated by argument to access the hardware + * clock. + */ static int -read_hardware_clock(const bool universal, bool *valid_p, time_t *systime_p){ -/*---------------------------------------------------------------------------- - Read the hardware clock and return the current time via argument. +read_hardware_clock(const bool universal, bool * valid_p, time_t * systime_p) +{ + struct tm tm; + int err; - Use the method indicated by argument to access the hardware clock. ------------------------------------------------------------------------------*/ - struct tm tm; - int err; + err = ur->read_hardware_clock(&tm); + if (err) + return err; - err = ur->read_hardware_clock(&tm); - if (err) - return err; + if (badyear) + read_date_from_file(&tm); - if (badyear) - read_date_from_file(&tm); + if (debug) + printf(_ + ("Time read from Hardware Clock: %4d/%.2d/%.2d %02d:%02d:%02d\n"), + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec); + mktime_tz(tm, universal, valid_p, systime_p); - if (debug) - printf (_("Time read from Hardware Clock: %4d/%.2d/%.2d %02d:%02d:%02d\n"), - tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - mktime_tz(tm, universal, valid_p, systime_p); - - return 0; + return 0; } - +/* + * Set the Hardware Clock to the time , in local time zone or UTC, + * according to . + */ static void set_hardware_clock(const time_t newtime, - const bool universal, - const bool testing) { -/*---------------------------------------------------------------------------- - Set the Hardware Clock to the time , in local time zone or UTC, - according to . -----------------------------------------------------------------------------*/ - struct tm new_broken_time; - /* Time to which we will set Hardware Clock, in broken down format, in - the time zone of caller's choice - */ + const bool universal, const bool testing) +{ + struct tm new_broken_time; + /* + * Time to which we will set Hardware Clock, in broken down format, + * in the time zone of caller's choice + */ - if (universal) - new_broken_time = *gmtime(&newtime); - else - new_broken_time = *localtime(&newtime); + if (universal) + new_broken_time = *gmtime(&newtime); + else + new_broken_time = *localtime(&newtime); - if (debug) - printf(_("Setting Hardware Clock to %.2d:%.2d:%.2d " - "= %ld seconds since 1969\n"), - new_broken_time.tm_hour, new_broken_time.tm_min, - new_broken_time.tm_sec, (long) newtime); + if (debug) + printf(_("Setting Hardware Clock to %.2d:%.2d:%.2d " + "= %ld seconds since 1969\n"), + new_broken_time.tm_hour, new_broken_time.tm_min, + new_broken_time.tm_sec, (long)newtime); - if (testing) - printf(_("Clock not changed - testing only.\n")); - else { - if (badyear) { - /* - * Write the real year to a file, then write a fake year - * between 1995 and 1998 to the RTC. This way, Award BIOS boots - * on 29 Feb 2000 thinking that it's 29 Feb 1996. - */ - write_date_to_file (&new_broken_time); - new_broken_time.tm_year = 95 + ((new_broken_time.tm_year+1) & 3); - } - ur->set_hardware_clock(&new_broken_time); - } + if (testing) + printf(_("Clock not changed - testing only.\n")); + else { + if (badyear) { + /* + * Write the real year to a file, then write a fake + * year between 1995 and 1998 to the RTC. This way, + * Award BIOS boots on 29 Feb 2000 thinking that + * it's 29 Feb 1996. + */ + write_date_to_file(&new_broken_time); + new_broken_time.tm_year = + 95 + ((new_broken_time.tm_year + 1) & 3); + } + ur->set_hardware_clock(&new_broken_time); + } } - - +/* + * Set the Hardware Clock to the time "sethwtime", in local time zone or + * UTC, according to "universal". + * + * Wait for a fraction of a second so that "sethwtime" is the value of the + * Hardware Clock as of system time "refsystime", which is in the past. For + * example, if "sethwtime" is 14:03:05 and "refsystime" is 12:10:04.5 and + * the current system time is 12:10:06.0: Wait .5 seconds (to make exactly 2 + * seconds since "refsystime") and then set the Hardware Clock to 14:03:07, + * thus getting a precise and retroactive setting of the clock. + * + * (Don't be confused by the fact that the system clock and the Hardware + * Clock differ by two hours in the above example. That's just to remind you + * that there are two independent time scales here). + * + * This function ought to be able to accept set times as fractional times. + * Idea for future enhancement. + */ static void set_hardware_clock_exact(const time_t sethwtime, - const struct timeval refsystime, - const bool universal, - const bool testing) { -/*---------------------------------------------------------------------------- - Set the Hardware Clock to the time "sethwtime", in local time zone or UTC, - according to "universal". - - Wait for a fraction of a second so that "sethwtime" is the value of - the Hardware Clock as of system time "refsystime", which is in the past. - For example, if "sethwtime" is 14:03:05 and "refsystime" is 12:10:04.5 - and the current system time is 12:10:06.0: Wait .5 seconds (to make - exactly 2 seconds since "refsystime") and then set the Hardware Clock - to 14:03:07, thus getting a precise and retroactive setting of the clock. - - (Don't be confused by the fact that the system clock and the Hardware - Clock differ by two hours in the above example. That's just to remind - you that there are two independent time scales here). - - This function ought to be able to accept set times as fractional times. - Idea for future enhancement. ------------------------------------------------------------------------------*/ - - time_t newhwtime; - struct timeval beginsystime, nowsystime; - double tdiff; + const struct timeval refsystime, + const bool universal, const bool testing) +{ + time_t newhwtime; + struct timeval beginsystime, nowsystime; + double tdiff; time_resync: - gettimeofday(&beginsystime, NULL); - tdiff = time_diff(beginsystime, refsystime); - newhwtime = sethwtime + (int) (tdiff + 0.5); - if (debug) - printf(_("Time elapsed since reference time has been %.6f seconds.\n" - "Delaying further to reach the new time.\n"), tdiff); + gettimeofday(&beginsystime, NULL); + tdiff = time_diff(beginsystime, refsystime); + newhwtime = sethwtime + (int)(tdiff + 0.5); + if (debug) + printf(_ + ("Time elapsed since reference time has been %.6f seconds.\n" + "Delaying further to reach the new time.\n"), tdiff); - /* - * Now delay some more until Hardware Clock time newhwtime arrives. The 0.5 s - * is because the Hardware Clock always sets to your set time plus 500 ms - * (because it is designed to update to the next second precisely 500 ms - * after you finish the setting). - */ - do { - gettimeofday(&nowsystime, NULL); - tdiff = time_diff(nowsystime, beginsystime); - if (tdiff < 0) - goto time_resync; /* probably backward time reset */ - if (tdiff > 0.1) - goto time_resync; /* probably forward time reset */ - beginsystime = nowsystime; - tdiff = time_diff(nowsystime, refsystime); - } while (newhwtime == sethwtime + (int) (tdiff + 0.5)); + /* + * Now delay some more until Hardware Clock time newhwtime arrives. + * The 0.5 s is because the Hardware Clock always sets to your set + * time plus 500 ms (because it is designed to update to the next + * second precisely 500 ms after you finish the setting). + */ + do { + gettimeofday(&nowsystime, NULL); + tdiff = time_diff(nowsystime, beginsystime); + if (tdiff < 0) + goto time_resync; /* probably backward time reset */ + if (tdiff > 0.1) + goto time_resync; /* probably forward time reset */ + beginsystime = nowsystime; + tdiff = time_diff(nowsystime, refsystime); + } while (newhwtime == sethwtime + (int)(tdiff + 0.5)); - set_hardware_clock(newhwtime, universal, testing); + set_hardware_clock(newhwtime, universal, testing); } - - +/* + * Put the time "systime" on standard output in display format. Except if + * hclock_valid == false, just tell standard output that we don't know what + * time it is. + * + * Include in the output the adjustment "sync_duration". + */ static void display_time(const bool hclock_valid, const time_t systime, - const double sync_duration) { -/*---------------------------------------------------------------------------- - Put the time "systime" on standard output in display format. - Except if hclock_valid == false, just tell standard output that we don't - know what time it is. + const double sync_duration) +{ + if (!hclock_valid) + fprintf(stderr, + _ + ("The Hardware Clock registers contain values that are " + "either invalid (e.g. 50th day of month) or beyond the range " + "we can handle (e.g. Year 2095).\n")); + else { + struct tm *lt; + char *format = "%c"; + char ctime_now[200]; - Include in the output the adjustment "sync_duration". ------------------------------------------------------------------------------*/ - if (!hclock_valid) - fprintf(stderr, _("The Hardware Clock registers contain values that are " - "either invalid (e.g. 50th day of month) or beyond the range " - "we can handle (e.g. Year 2095).\n")); - else { - struct tm *lt; - char *format = "%c"; - char ctime_now[200]; - - lt = localtime(&systime); - strftime(ctime_now, sizeof(ctime_now), format, lt); - printf(_("%s %.6f seconds\n"), ctime_now, -(sync_duration)); - } + lt = localtime(&systime); + strftime(ctime_now, sizeof(ctime_now), format, lt); + printf(_("%s %.6f seconds\n"), ctime_now, -(sync_duration)); + } } - - -static int -interpret_date_string(const char *date_opt, time_t * const time_p) { -/*---------------------------------------------------------------------------- - Interpret the value of the --date option, which is something like - "13:05:01". In fact, it can be any of the myriad ASCII strings that specify - a time which the "date" program can understand. The date option value in - question is our "dateopt" argument. - - The specified time is in the local time zone. - - Our output, "*time_p", is a seconds-into-epoch time. - - We use the "date" program to interpret the date string. "date" must be - runnable by issuing the command "date" to the /bin/sh shell. That means - in must be in the current PATH. - - If anything goes wrong (and many things can), we return return code - 10 and arbitrary *time_p. Otherwise, return code is 0 and *time_p - is valid. -----------------------------------------------------------------------------*/ +/* + * Interpret the value of the --date option, which is something like + * "13:05:01". In fact, it can be any of the myriad ASCII strings that + * specify a time which the "date" program can understand. The date option + * value in question is our "dateopt" argument. + * + * The specified time is in the local time zone. + * + * Our output, "*time_p", is a seconds-into-epoch time. + * + * We use the "date" program to interpret the date string. "date" must be + * runnable by issuing the command "date" to the /bin/sh shell. That means + * in must be in the current PATH. + * + * If anything goes wrong (and many things can), we return return code 10 + * and arbitrary *time_p. Otherwise, return code is 0 and *time_p is valid. + */ +static int interpret_date_string(const char *date_opt, time_t * const time_p) +{ FILE *date_child_fp; char date_resp[100]; - const char magic[]="seconds-into-epoch="; + const char magic[] = "seconds-into-epoch="; char date_command[100]; - int retcode; /* our eventual return code */ - int rc; /* local return code */ + int retcode; /* our eventual return code */ + int rc; /* local return code */ if (date_opt == NULL) { fprintf(stderr, _("No --date option specified.\n")); @@ -624,8 +626,9 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { /* Quotes in date_opt would ruin the date command we construct. */ if (strchr(date_opt, '"') != NULL) { fprintf(stderr, - _("The value of the --date option is not a valid date.\n" - "In particular, it contains quotation marks.\n")); + _ + ("The value of the --date option is not a valid date.\n" + "In particular, it contains quotation marks.\n")); return 12; } @@ -642,10 +645,10 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { } if (!fgets(date_resp, sizeof(date_resp), date_child_fp)) - date_resp[0] = '\0'; /* in case fgets fails */ + date_resp[0] = '\0'; /* in case fgets fails */ if (debug) printf(_("response from date command = %s\n"), date_resp); - if (strncmp(date_resp, magic, sizeof(magic)-1) != 0) { + if (strncmp(date_resp, magic, sizeof(magic) - 1) != 0) { fprintf(stderr, _("The date command issued by %s returned " "unexpected results.\n" "The command was:\n %s\n" @@ -654,7 +657,7 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { retcode = 8; } else { long seconds_since_epoch; - rc = sscanf(date_resp + sizeof(magic)-1, "%ld", + rc = sscanf(date_resp + sizeof(magic) - 1, "%ld", &seconds_since_epoch); if (rc < 1) { fprintf(stderr, @@ -671,7 +674,7 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { if (debug) printf(_("date string %s equates to " "%ld seconds since 1969.\n"), - date_opt, (long) *time_p); + date_opt, (long)*time_p); } } pclose(date_child_fp); @@ -679,173 +682,181 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { return retcode; } - - +/* + * Set the System Clock to time 'newtime'. + * + * Also set the kernel time zone value to the value indicated by the TZ + * environment variable and/or /usr/lib/zoneinfo/, interpreted as tzset() + * would interpret them. + * + * EXCEPT: if hclock_valid is false, just issue an error message saying + * there is no valid time in the Hardware Clock to which to set the system + * time. + * + * If 'testing' is true, don't actually update anything -- just say we would + * have. + */ static int set_system_clock(const bool hclock_valid, const time_t newtime, - const bool testing) { -/*---------------------------------------------------------------------------- - Set the System Clock to time 'newtime'. + const bool testing) +{ + int retcode; - 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 (!hclock_valid) { + fprintf(stderr, + _ + ("The Hardware Clock does not contain a valid time, so " + "we cannot set the System Time from it.\n")); + retcode = 1; + } else { + struct timeval tv; + struct tm *broken; + int minuteswest; + int rc; - 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. + tv.tv_sec = newtime; + tv.tv_usec = 0; - If 'testing' is true, don't actually update anything -- just say we - would have. ------------------------------------------------------------------------------*/ - int retcode; - - if (!hclock_valid) { - fprintf(stderr, _("The Hardware Clock does not contain a valid time, so " - "we cannot set the System Time from it.\n")); - retcode = 1; - } else { - struct timeval tv; - struct tm *broken; - int minuteswest; - int rc; - - tv.tv_sec = newtime; - tv.tv_usec = 0; - - broken = localtime(&newtime); + broken = localtime(&newtime); #ifdef HAVE_TM_GMTOFF - minuteswest = -broken->tm_gmtoff/60; /* GNU extension */ + minuteswest = -broken->tm_gmtoff / 60; /* GNU extension */ #else - minuteswest = timezone/60; - if (broken->tm_isdst) - minuteswest -= 60; + minuteswest = timezone / 60; + if (broken->tm_isdst) + minuteswest -= 60; #endif - if (debug) { - printf(_("Calling settimeofday:\n")); - printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"), - (long) tv.tv_sec, (long) tv.tv_usec); - printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest); - } - if (testing) { - printf(_("Not setting system clock because running in test mode.\n")); - retcode = 0; - } else { - const struct timezone tz = { minuteswest, 0 }; + if (debug) { + printf(_("Calling settimeofday:\n")); + printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"), + (long)tv.tv_sec, (long)tv.tv_usec); + printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest); + } + if (testing) { + printf(_ + ("Not setting system clock because running in test mode.\n")); + retcode = 0; + } else { + const struct timezone tz = { minuteswest, 0 }; - rc = settimeofday(&tv, &tz); - if (rc) { - if (errno == EPERM) { - fprintf(stderr, - _("Must be superuser to set system clock.\n")); - retcode = EX_NOPERM; - } else { - outsyserr(_("settimeofday() failed")); - retcode = 1; - } - } else retcode = 0; - } - } - return retcode; + rc = settimeofday(&tv, &tz); + if (rc) { + if (errno == EPERM) { + fprintf(stderr, + _ + ("Must be superuser to set system clock.\n")); + retcode = EX_NOPERM; + } else { + outsyserr(_("settimeofday() failed")); + retcode = 1; + } + } else + retcode = 0; + } + } + return retcode; } +/* + * Reset the System Clock from local time to UTC, based on its current value + * and the timezone unless universal is TRUE. + * + * Also set the kernel time zone value to the value indicated by the TZ + * environment variable and/or /usr/lib/zoneinfo/, interpreted as tzset() + * would interpret them. + * + * If 'testing' is true, don't actually update anything -- just say we would + * have. + */ +static int set_system_clock_timezone(const bool universal, const bool testing) +{ + int retcode; + struct timeval tv; + struct tm *broken; + int minuteswest; + int rc; -static int -set_system_clock_timezone(const bool universal, const bool testing) { -/*---------------------------------------------------------------------------- - Reset the System Clock from local time to UTC, based on its current - value and the timezone unless universal is TRUE. + gettimeofday(&tv, NULL); + if (debug) { + struct tm broken_time; + char ctime_now[200]; - 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. + 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); + } - If 'testing' is true, don't actually update anything -- just say we - would have. ------------------------------------------------------------------------------*/ - int retcode; - struct timeval tv; - struct tm *broken; - int minuteswest; - int rc; - - gettimeofday(&tv, NULL); - if (debug) { - struct tm broken_time; - char ctime_now[200]; - - broken_time = *gmtime(&tv.tv_sec); - strftime(ctime_now, sizeof(ctime_now), "%Y/%m/%d %H:%M:%S", &broken_time); - printf(_("Current system time: %ld = %s\n"), (long) tv.tv_sec, ctime_now); - } - - broken = localtime(&tv.tv_sec); + broken = localtime(&tv.tv_sec); #ifdef HAVE_TM_GMTOFF - minuteswest = -broken->tm_gmtoff/60; /* GNU extension */ + minuteswest = -broken->tm_gmtoff / 60; /* GNU extension */ #else - minuteswest = timezone/60; - if (broken->tm_isdst) - minuteswest -= 60; + minuteswest = timezone / 60; + if (broken->tm_isdst) + minuteswest -= 60; #endif - gettimeofday(&tv, NULL); - if (!universal) - tv.tv_sec += minuteswest * 60; + gettimeofday(&tv, NULL); + if (!universal) + tv.tv_sec += minuteswest * 60; - if (debug) { - struct tm broken_time; - char ctime_now[200]; + 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); + 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 }; + 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; + rc = settimeofday(&tv, &tz); + if (rc) { + if (errno == EPERM) { + fprintf(stderr, + _ + ("Must be superuser to set system clock.\n")); + retcode = EX_NOPERM; + } else { + outsyserr(_("settimeofday() failed")); + retcode = 1; + } + } else + retcode = 0; + } + return retcode; } - +/* + * Update the drift factor in <*adjtime_p> to reflect the fact that the + * Hardware Clock was calibrated to and before that was set to + * . + * + * We record in the adjtime file the time at which we last calibrated the + * clock so we can compute the drift rate each time we calibrate. + * + * EXCEPT: if is false, assume Hardware Clock was not set + * before to anything meaningful and regular adjustments have not been done, + * so don't adjust the drift factor. + */ static void adjust_drift_factor(struct adjtime *adjtime_p, - const time_t nowtime, - const bool hclock_valid, - const time_t hclocktime, - const double sync_delay) { -/*------------------------------------------------------------------------ - Update the drift factor in <*adjtime_p> to reflect the fact that the - Hardware Clock was calibrated to and before that was set - to . - - We record in the adjtime file the time at which we last calibrated - the clock so we can compute the drift rate each time we calibrate. - - EXCEPT: if is false, assume Hardware Clock was not set - before to anything meaningful and regular adjustments have not been - done, so don't adjust the drift factor. - ------------------------------------------------------------------------*/ + const time_t nowtime, + const bool hclock_valid, + const time_t hclocktime, const double sync_delay) +{ if (!hclock_valid) { if (debug) printf(_("Not adjusting drift factor because the " @@ -867,9 +878,9 @@ adjust_drift_factor(struct adjtime *adjtime_p, * At adjustment time we adjust the hardware clock according * to the contents of /etc/adjtime. * - * At calibration time we set the hardware clock and - * update /etc/adjtime, that is, for each calibration - * (except the first) we also do an adjustment. + * At calibration time we set the hardware clock and update + * /etc/adjtime, that is, for each calibration (except the + * first) we also do an adjustment. * * We are now at calibration time. * @@ -887,21 +898,21 @@ adjust_drift_factor(struct adjtime *adjtime_p, /* Days since last adjustment (in hardware clock time) */ adj_days = (double)(hclocktime - adjtime_p->last_adj_time) - / sec_per_day; + / sec_per_day; /* Expected drift (sec) since last adjustment */ exp_drift = adj_days * adjtime_p->drift_factor - + adjtime_p->not_adjusted; + + adjtime_p->not_adjusted; /* Uncorrected drift (sec) since last calibration */ unc_drift = (double)(nowtime - hclocktime) - + sync_delay - exp_drift; + + sync_delay - exp_drift; /* Days since last calibration (in hardware clock time) */ cal_days = ((double)(adjtime_p->last_adj_time - - adjtime_p->last_calib_time) + - adjtime_p->last_calib_time) + adjtime_p->not_adjusted) - / (sec_per_day * atime_per_htime) + adj_days; + / (sec_per_day * atime_per_htime) + adj_days; /* Amount to add to previous drift factor */ factor_adjust = unc_drift / cal_days; @@ -912,9 +923,8 @@ adjust_drift_factor(struct adjtime *adjtime_p, "%f seconds/day.\n" "Adjusting drift factor by %f seconds/day\n"), unc_drift, - (int) (nowtime - adjtime_p->last_calib_time), - adjtime_p->drift_factor, - factor_adjust); + (int)(nowtime - adjtime_p->last_calib_time), + adjtime_p->drift_factor, factor_adjust); adjtime_p->drift_factor += factor_adjust; } @@ -927,383 +937,403 @@ adjust_drift_factor(struct adjtime *adjtime_p, adjtime_p->dirty = TRUE; } - - +/* + * Do the drift adjustment calculation. + * + * The way we have to set the clock, we need the adjustment in two parts: + * + * 1) an integer number of seconds (return as *adjustment_p) + * 2) a positive fraction of a second (less than 1) (return as *retro_p) + * + * The sum of these two values is the adjustment needed. Positive means to + * advance the clock or insert seconds. Negative means to retard the clock + * or remove seconds. + */ static void calculate_adjustment(const double factor, - const time_t last_time, - const double not_adjusted, - const time_t systime, - int *adjustment_p, - double *retro_p) { -/*---------------------------------------------------------------------------- - Do the drift adjustment calculation. + const time_t last_time, + const double not_adjusted, + const time_t systime, int *adjustment_p, double *retro_p) +{ + double exact_adjustment; - The way we have to set the clock, we need the adjustment in two parts: + exact_adjustment = + ((double)(systime - last_time)) * factor / (24 * 60 * 60) + + not_adjusted; + *adjustment_p = FLOOR(exact_adjustment); - 1) an integer number of seconds (return as *adjustment_p) - - 2) a positive fraction of a second (less than 1) (return as *retro_p) - - The sum of these two values is the adjustment needed. Positive means to - advance the clock or insert seconds. Negative means to retard the clock - or remove seconds. -----------------------------------------------------------------------------*/ - double exact_adjustment; - - exact_adjustment = ((double) (systime - last_time)) * factor / (24 * 60 * 60) - + not_adjusted; - *adjustment_p = FLOOR(exact_adjustment); - - *retro_p = exact_adjustment - (double) *adjustment_p; - if (debug) { - printf (_("Time since last adjustment is %d seconds\n"), - (int) (systime - last_time)); - printf (_("Need to insert %d seconds and refer time back " - "%.6f seconds ago\n"), - *adjustment_p, *retro_p); - } + *retro_p = exact_adjustment - (double)*adjustment_p; + if (debug) { + printf(_("Time since last adjustment is %d seconds\n"), + (int)(systime - last_time)); + printf(_("Need to insert %d seconds and refer time back " + "%.6f seconds ago\n"), *adjustment_p, *retro_p); + } } +/* + * Write the contents of the structure to its disk file. + * + * But if the contents are clean (unchanged since read from disk), don't + * bother. + */ +static void save_adjtime(const struct adjtime adjtime, const bool testing) +{ + char newfile[412]; /* Stuff to write to disk file */ + if (adjtime.dirty) { + /* + * snprintf is not always available, but this is safe as + * long as libc does not use more than 100 positions for %ld + * or %f + */ + sprintf(newfile, "%f %ld %f\n%ld\n%s\n", + adjtime.drift_factor, + (long)adjtime.last_adj_time, + adjtime.not_adjusted, + (long)adjtime.last_calib_time, + (adjtime.local_utc == UTC) ? "UTC" : "LOCAL"); -static void -save_adjtime(const struct adjtime adjtime, const bool testing) { -/*----------------------------------------------------------------------------- - Write the contents of the structure to its disk file. + if (testing) { + printf(_ + ("Not updating adjtime file because of testing mode.\n")); + printf(_("Would have written the following to %s:\n%s"), + adj_file_name, newfile); + } else { + FILE *adjfile; + int err = 0; - But if the contents are clean (unchanged since read from disk), don't - bother. ------------------------------------------------------------------------------*/ - char newfile[412]; /* Stuff to write to disk file */ - - if (adjtime.dirty) { - /* snprintf is not always available, but this is safe - as long as libc does not use more than 100 positions for %ld or %f */ - sprintf(newfile, "%f %ld %f\n%ld\n%s\n", - adjtime.drift_factor, - (long) adjtime.last_adj_time, - adjtime.not_adjusted, - (long) adjtime.last_calib_time, - (adjtime.local_utc == UTC) ? "UTC" : "LOCAL"); - - if (testing) { - printf(_("Not updating adjtime file because of testing mode.\n")); - printf(_("Would have written the following to %s:\n%s"), - adj_file_name, newfile); - } else { - FILE *adjfile; - int err = 0; - - adjfile = fopen(adj_file_name, "w"); - if (adjfile == NULL) { - outsyserr(_("Could not open file with the clock adjustment parameters " - "in it (%s) for writing"), adj_file_name); - err = 1; - } else { - if (fputs(newfile, adjfile) < 0) { - outsyserr(_("Could not update file with the clock adjustment " - "parameters (%s) in it"), adj_file_name); - err = 1; - } - if (fclose(adjfile) < 0) { - outsyserr(_("Could not update file with the clock adjustment " - "parameters (%s) in it"), adj_file_name); - err = 1; - } - } - if (err) - fprintf(stderr, _("Drift adjustment parameters not updated.\n")); - } - } + adjfile = fopen(adj_file_name, "w"); + if (adjfile == NULL) { + outsyserr(_ + ("Could not open file with the clock adjustment parameters " + "in it (%s) for writing"), + adj_file_name); + err = 1; + } else { + if (fputs(newfile, adjfile) < 0) { + outsyserr(_ + ("Could not update file with the clock adjustment " + "parameters (%s) in it"), + adj_file_name); + err = 1; + } + if (fclose(adjfile) < 0) { + outsyserr(_ + ("Could not update file with the clock adjustment " + "parameters (%s) in it"), + adj_file_name); + err = 1; + } + } + if (err) + fprintf(stderr, + _ + ("Drift adjustment parameters not updated.\n")); + } + } } - - +/* + * Do the adjustment requested, by 1) setting the Hardware Clock (if + * necessary), and 2) updating the last-adjusted time in the adjtime + * structure. + * + * Do not update anything if the Hardware Clock does not currently present a + * valid time. + * + * Arguments and are current values from the adjtime + * file. + * + * means the Hardware Clock contains a valid time, and that + * time is . + * + * is the current system time (to be precise, it is the system + * time at the time was read, which due to computational delay + * could be a short time ago). + * + * : the Hardware Clock is kept in UTC. + * + * : We are running in test mode (no updating of clock). + * + * We do not bother to update the clock if the adjustment would be less than + * one second. This is to avoid cumulative error and needless CPU hogging + * (remember we use an infinite loop for some timing) if the user runs us + * frequently. + */ static void do_adjustment(struct adjtime *adjtime_p, - const bool hclock_valid, const time_t hclocktime, - const struct timeval read_time, - const bool universal, const bool testing) { -/*--------------------------------------------------------------------------- - Do the adjustment requested, by 1) setting the Hardware Clock (if - necessary), and 2) updating the last-adjusted time in the adjtime - structure. - - Do not update anything if the Hardware Clock does not currently present - a valid time. - - arguments and are current values from the adjtime - file. - - means the Hardware Clock contains a valid time, and that - time is . - - is the current system time (to be precise, it is the system - time at the time was read, which due to computational delay - could be a short time ago). - - : the Hardware Clock is kept in UTC. - - : We are running in test mode (no updating of clock). - - We do not bother to update the clock if the adjustment would be less than - one second. This is to avoid cumulative error and needless CPU hogging - (remember we use an infinite loop for some timing) if the user runs us - frequently. - -----------------------------------------------------------------------------*/ - if (!hclock_valid) { - fprintf(stderr, _("The Hardware Clock does not contain a valid time, " - "so we cannot adjust it.\n")); - adjtime_p->last_calib_time = 0; /* calibration startover is required */ - adjtime_p->last_adj_time = 0; - adjtime_p->not_adjusted = 0; - adjtime_p->dirty = TRUE; - } else if (adjtime_p->last_adj_time == 0) { - if (debug) - printf(_("Not setting clock because last adjustment time is zero, " - "so history is bad.")); - } else { - int adjustment; - /* Number of seconds we must insert in the Hardware Clock */ - double retro; - /* Fraction of second we have to remove from clock after inserting - whole seconds. - */ - calculate_adjustment(adjtime_p->drift_factor, - adjtime_p->last_adj_time, - adjtime_p->not_adjusted, - hclocktime, - &adjustment, &retro); - if (adjustment > 0 || adjustment < -1) { - set_hardware_clock_exact(hclocktime + adjustment, - time_inc(read_time, -retro), - universal, testing); - adjtime_p->last_adj_time = hclocktime + adjustment; - adjtime_p->not_adjusted = 0; - adjtime_p->dirty = TRUE; - } else - if (debug) - printf(_("Needed adjustment is less than one second, " - "so not setting clock.\n")); - } + const bool hclock_valid, const time_t hclocktime, + const struct timeval read_time, + const bool universal, const bool testing) +{ + if (!hclock_valid) { + fprintf(stderr, + _("The Hardware Clock does not contain a valid time, " + "so we cannot adjust it.\n")); + adjtime_p->last_calib_time = 0; /* calibration startover is required */ + adjtime_p->last_adj_time = 0; + adjtime_p->not_adjusted = 0; + adjtime_p->dirty = TRUE; + } else if (adjtime_p->last_adj_time == 0) { + if (debug) + printf(_ + ("Not setting clock because last adjustment time is zero, " + "so history is bad.")); + } else { + int adjustment; + /* Number of seconds we must insert in the Hardware Clock */ + double retro; + /* + * Fraction of second we have to remove from clock after + * inserting whole seconds. + */ + calculate_adjustment(adjtime_p->drift_factor, + adjtime_p->last_adj_time, + adjtime_p->not_adjusted, + hclocktime, &adjustment, &retro); + if (adjustment > 0 || adjustment < -1) { + set_hardware_clock_exact(hclocktime + adjustment, + time_inc(read_time, -retro), + universal, testing); + adjtime_p->last_adj_time = hclocktime + adjustment; + adjtime_p->not_adjusted = 0; + adjtime_p->dirty = TRUE; + } else if (debug) + printf(_("Needed adjustment is less than one second, " + "so not setting clock.\n")); + } } +static void determine_clock_access_method(const bool user_requests_ISA) +{ + ur = NULL; - -static void -determine_clock_access_method(const bool user_requests_ISA) { - - ur = NULL; - - if (user_requests_ISA) - ur = probe_for_cmos_clock(); + if (user_requests_ISA) + ur = probe_for_cmos_clock(); #ifdef __linux__ - if (!ur) - ur = probe_for_rtc_clock(); + if (!ur) + ur = probe_for_rtc_clock(); #endif - if (!ur) - ur = probe_for_kd_clock(); + if (!ur) + ur = probe_for_kd_clock(); - if (!ur && !user_requests_ISA) - ur = probe_for_cmos_clock(); + if (!ur && !user_requests_ISA) + ur = probe_for_cmos_clock(); - if (debug) { - if (ur) - printf(_("Using %s.\n"), ur->interface_name); - else - printf(_("No usable clock interface found.\n")); - } + if (debug) { + if (ur) + printf(_("Using %s.\n"), ur->interface_name); + else + printf(_("No usable clock interface found.\n")); + } } +/* + * Do all the normal work of hwclock - read, set clock, etc. + * + * Issue output to stdout and error message to stderr where appropriate. + * + * Return rc == 0 if everything went OK, rc != 0 if not. + */ static int manipulate_clock(const bool show, const bool adjust, const bool noadjfile, - const bool set, const time_t set_time, - const bool hctosys, const bool systohc, const bool systz, - const struct timeval startup_time, - const bool utc, const bool local_opt, - const bool testing, const bool predict) { -/*--------------------------------------------------------------------------- - Do all the normal work of hwclock - read, set clock, etc. + const bool set, const time_t set_time, + const bool hctosys, const bool systohc, const bool systz, + const struct timeval startup_time, + const bool utc, const bool local_opt, + const bool testing, const bool predict) +{ + /* Contents of the adjtime file, or what they should be. */ + struct adjtime adjtime; + bool universal; + /* Set if user lacks necessary authorization to access the clock */ + bool no_auth; + /* The time at which we read the Hardware Clock */ + struct timeval read_time; + /* + * The Hardware Clock gives us a valid time, or at + * least something close enough to fool mktime(). + */ + bool hclock_valid = FALSE; + /* + * The time the hardware clock had just after we + * synchronized to its next clock tick when we + * started up. Defined only if hclock_valid is true. + */ + time_t hclocktime = 0; + /* local return code */ + int rc; - Issue output to stdout and error message to stderr where appropriate. - - Return rc == 0 if everything went OK, rc != 0 if not. -----------------------------------------------------------------------------*/ - struct adjtime adjtime; - /* Contents of the adjtime file, or what they should be. */ - int rc; /* local return code */ - bool no_auth; /* User lacks necessary authorization to access the clock */ - - if (!systz && !predict) { - no_auth = ur->get_permissions(); - if (no_auth) - return EX_NOPERM; - } - - if (!noadjfile && (adjust || set || systohc || (!utc && !local_opt) || predict)) { - rc = read_adjtime(&adjtime); - if (rc) - return rc; - } else { - /* A little trick to avoid reading the file if we don't have to */ - adjtime.dirty = FALSE; - rc = 0; - } - - { - const bool universal = hw_clock_is_utc(utc, local_opt, adjtime); - - if ((set || systohc || adjust) && - (adjtime.local_utc == UTC) != universal) { - adjtime.local_utc = universal ? UTC : LOCAL; - adjtime.dirty = TRUE; - } - - { - struct timeval read_time; - /* The time at which we read the Hardware Clock */ - - bool hclock_valid = FALSE; - /* The Hardware Clock gives us a valid time, or at least something - close enough to fool mktime(). - */ - - time_t hclocktime = 0; - /* The time the hardware clock had just after we - synchronized to its next clock tick when we started up. - Defined only if hclock_valid is true. - */ - - if (show || adjust || hctosys || (!noadjfile && !systz && !predict)) { - /* data from HW-clock are required */ - rc = synchronize_to_clock_tick(); - - /* 2 = synchronization timeout. We don't error out if the user is - attempting to set the RTC - the RTC could be functioning but - contain invalid time data so we still want to allow a user to set - the RTC time. - */ - - if (rc && rc != 2 && !set && !systohc) - return EX_IOERR; - gettimeofday(&read_time, NULL); - - /* If we can't synchronize to a clock tick, we likely can't read - from the RTC so don't bother reading it again. */ - if (!rc) { - rc = read_hardware_clock(universal, &hclock_valid, &hclocktime); - if (rc && !set && !systohc) - return EX_IOERR; - } + if (!systz && !predict) { + no_auth = ur->get_permissions(); + if (no_auth) + return EX_NOPERM; } - if (show) { - display_time(hclock_valid, hclocktime, - time_diff(read_time, startup_time)); - } else if (set) { - set_hardware_clock_exact(set_time, startup_time, - universal, testing); - if (!noadjfile) - adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime, - time_diff(read_time, startup_time)); - } else if (adjust) { - do_adjustment(&adjtime, hclock_valid, hclocktime, - read_time, universal, testing); - } else if (systohc) { - struct timeval nowtime, reftime; - /* We can only set_hardware_clock_exact to a whole seconds - time, so we set it with reference to the most recent - whole seconds time. - */ - gettimeofday(&nowtime, NULL); - reftime.tv_sec = nowtime.tv_sec; - reftime.tv_usec = 0; + if (!noadjfile + && (adjust || set || systohc || (!utc && !local_opt) || predict)) { + rc = read_adjtime(&adjtime); + if (rc) + return rc; + } else { + /* A little trick to avoid reading the file if we don't have to */ + adjtime.dirty = FALSE; + rc = 0; + } - set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, - universal, testing); - if (!noadjfile) - adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, - hclocktime, (double) read_time.tv_usec / 1E6); - } else if (hctosys) { - rc = set_system_clock(hclock_valid, hclocktime, testing); - if (rc) { - printf(_("Unable to set system clock.\n")); - return rc; - } + universal = hw_clock_is_utc(utc, local_opt, adjtime); + + if ((set || systohc || adjust) && + (adjtime.local_utc == UTC) != universal) { + adjtime.local_utc = universal ? UTC : LOCAL; + adjtime.dirty = TRUE; + } + + if (show || adjust || hctosys || (!noadjfile && !systz && !predict)) { + /* data from HW-clock are required */ + rc = synchronize_to_clock_tick(); + + /* + * 2 = synchronization timeout. We don't + * error out if the user is attempting to + * set the RTC - the RTC could be + * functioning but contain invalid time data + * so we still want to allow a user to set + * the RTC time. + */ + if (rc && rc != 2 && !set && !systohc) + return EX_IOERR; + gettimeofday(&read_time, NULL); + + /* + * If we can't synchronize to a clock tick, + * we likely can't read from the RTC so + * don't bother reading it again. + */ + if (!rc) { + rc = read_hardware_clock(universal, + &hclock_valid, &hclocktime); + if (rc && !set && !systohc) + return EX_IOERR; + } + } + + if (show) { + display_time(hclock_valid, hclocktime, + time_diff(read_time, startup_time)); + } else if (set) { + set_hardware_clock_exact(set_time, startup_time, + universal, testing); + if (!noadjfile) + adjust_drift_factor(&adjtime, set_time, + hclock_valid, + hclocktime, + time_diff(read_time, startup_time)); + } else if (adjust) { + do_adjustment(&adjtime, hclock_valid, + hclocktime, read_time, universal, testing); + } else if (systohc) { + struct timeval nowtime, reftime; + /* + * We can only set_hardware_clock_exact to a + * whole seconds time, so we set it with + * reference to the most recent whole + * seconds time. + */ + gettimeofday(&nowtime, NULL); + reftime.tv_sec = nowtime.tv_sec; + reftime.tv_usec = 0; + set_hardware_clock_exact((time_t) + reftime.tv_sec, + reftime, universal, testing); + if (!noadjfile) + adjust_drift_factor(&adjtime, (time_t) + reftime.tv_sec, + hclock_valid, hclocktime, (double) + read_time.tv_usec / 1E6); + } else if (hctosys) { + rc = set_system_clock(hclock_valid, hclocktime, testing); + if (rc) { + printf(_("Unable to set system clock.\n")); + return rc; + } } else if (systz) { - rc = set_system_clock_timezone(universal, testing); - if (rc) { - printf(_("Unable to set system clock.\n")); - return rc; - } - } else if (predict) { - int adjustment; - double retro; + rc = set_system_clock_timezone(universal, testing); + if (rc) { + printf(_("Unable to set system clock.\n")); + return rc; + } + } else if (predict) { + int adjustment; + double retro; - calculate_adjustment(adjtime.drift_factor, - adjtime.last_adj_time, - adjtime.not_adjusted, - set_time, - &adjustment, &retro); - if (debug) { - printf(_("At %ld seconds after 1969, RTC is predicted to read %ld seconds after 1969.\n"), - set_time, set_time + adjustment); - } - display_time(TRUE, set_time + adjustment, -retro); - } - if (!noadjfile) - save_adjtime(adjtime, testing); - } - } - return 0; + calculate_adjustment(adjtime.drift_factor, + adjtime.last_adj_time, + adjtime.not_adjusted, + set_time, &adjustment, &retro); + if (debug) { + printf(_ + ("At %ld seconds after 1969, RTC is predicted to read %ld seconds after 1969.\n"), + set_time, set_time + adjustment); + } + display_time(TRUE, set_time + adjustment, -retro); + } + if (!noadjfile) + save_adjtime(adjtime, testing); + return 0; } - +/* + * Get or set the Hardware Clock epoch value in the kernel, as appropriate. + * , , and are hwclock invocation options. + * + * == -1 if the user did not specify an "epoch" option. + */ #ifdef __linux__ static void manipulate_epoch(const bool getepoch, const bool setepoch, - const int epoch_opt, const bool testing) { -/*---------------------------------------------------------------------------- - Get or set the Hardware Clock epoch value in the kernel, as appropriate. - , , and are hwclock invocation options. - - == -1 if the user did not specify an "epoch" option. - ------------------------------------------------------------------------------*/ - /* - Maintenance note: This should work on non-Alpha machines, but the - evidence today (98.03.04) indicates that the kernel only keeps the - epoch value on Alphas. If that is ever fixed, this function should be - changed. - */ - + const int epoch_opt, const bool testing) +{ + /* + * Maintenance note: This should work on non-Alpha machines, but the + * evidence today (98.03.04) indicates that the kernel only keeps + * the epoch value on Alphas. If that is ever fixed, this function + * should be changed. + */ #ifndef __alpha__ - fprintf(stderr, _("The kernel keeps an epoch value for the Hardware Clock " - "only on an Alpha machine.\nThis copy of hwclock was built for " - "a machine other than Alpha\n(and thus is presumably not running " - "on an Alpha now). No action taken.\n")); + fprintf(stderr, + _("The kernel keeps an epoch value for the Hardware Clock " + "only on an Alpha machine.\nThis copy of hwclock was built for " + "a machine other than Alpha\n(and thus is presumably not running " + "on an Alpha now). No action taken.\n")); #else - if (getepoch) { - unsigned long epoch; + if (getepoch) { + unsigned long epoch; - if (get_epoch_rtc(&epoch, 0)) - fprintf(stderr, _("Unable to get the epoch value from the kernel.\n")); - else - printf(_("Kernel is assuming an epoch value of %lu\n"), epoch); - } else if (setepoch) { - if (epoch_opt == -1) - fprintf(stderr, _("To set the epoch value, you must use the 'epoch' " - "option to tell to what value to set it.\n")); - else if (testing) - printf(_("Not setting the epoch to %d - testing only.\n"), - epoch_opt); - else if (set_epoch_rtc(epoch_opt)) - printf(_("Unable to set the epoch value in the kernel.\n")); - } + if (get_epoch_rtc(&epoch, 0)) + fprintf(stderr, + _ + ("Unable to get the epoch value from the kernel.\n")); + else + printf(_("Kernel is assuming an epoch value of %lu\n"), + epoch); + } else if (setepoch) { + if (epoch_opt == -1) + fprintf(stderr, + _ + ("To set the epoch value, you must use the 'epoch' " + "option to tell to what value to set it.\n")); + else if (testing) + printf(_ + ("Not setting the epoch to %d - testing only.\n"), + epoch_opt); + else if (set_epoch_rtc(epoch_opt)) + printf(_ + ("Unable to set the epoch value in the kernel.\n")); + } #endif } #endif @@ -1314,123 +1344,118 @@ manipulate_epoch(const bool getepoch, const bool setepoch, #define RTC_DEV "/dev/rtc" #endif -static void -out_version(void) { +static void out_version(void) +{ printf(_("%s from %s\n"), MYNAME, PACKAGE_STRING); } /* - usage - Output (error and) usage information + * 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; - 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; - usageto = fmt ? stderr : stdout; - - fprintf( usageto, _( - "hwclock - query and set the hardware clock (RTC)\n\n" - "Usage: hwclock [function] [options...]\n\n" - "Functions:\n" - " -h | --help show this help\n" - " -r | --show read hardware clock and print result\n" - " --set set the rtc to the time given with --date\n" - " -s | --hctosys set the system time from the hardware clock\n" - " -w | --systohc set the hardware clock to the current system time\n" - " --systz set the system time based on the current timezone\n" - " --adjust adjust the rtc to account for systematic drift since\n" - " the clock was last set or adjusted\n" + fprintf(usageto, + _("hwclock - query and set the hardware clock (RTC)\n\n" + "Usage: hwclock [function] [options...]\n\n" "Functions:\n" + " -h | --help show this help\n" + " -r | --show read hardware clock and print result\n" + " --set set the rtc to the time given with --date\n" + " -s | --hctosys set the system time from the hardware clock\n" + " -w | --systohc set the hardware clock to the current system time\n" + " --systz set the system time based on the current timezone\n" + " --adjust adjust the rtc to account for systematic drift since\n" + " the clock was last set or adjusted\n" #ifdef __linux__ - " --getepoch print out the kernel's hardware clock epoch value\n" - " --setepoch set the kernel's hardware clock epoch value to the \n" - " value given with --epoch\n" + " --getepoch print out the kernel's hardware clock epoch value\n" + " --setepoch set the kernel's hardware clock epoch value to the \n" + " value given with --epoch\n" #endif - " --predict predict rtc reading at time given with --date\n" - " -v | --version print out the version of hwclock to stdout\n" - "\nOptions: \n" - " -u | --utc the hardware clock is kept in UTC\n" - " --localtime the hardware clock is kept in local time\n" + " --predict predict rtc reading at time given with --date\n" + " -v | --version print out the version of hwclock to stdout\n" + "\nOptions: \n" + " -u | --utc the hardware clock is kept in UTC\n" + " --localtime the hardware clock is kept in local time\n" #ifdef __linux__ - " -f | --rtc=path special /dev/... file to use instead of default\n" + " -f | --rtc=path special /dev/... file to use instead of default\n" #endif - " --directisa access the ISA bus directly instead of %s\n" - " --badyear ignore rtc's year because the bios is broken\n" - " --date specifies the time to which to set the hardware clock\n" - " --epoch=year specifies the year which is the beginning of the \n" - " hardware clock's epoch value\n" - " --noadjfile do not access /etc/adjtime. Requires the use of\n" - " either --utc or --localtime\n" - " --adjfile=path specifies the path to the adjust file (default is\n" - " /etc/adjtime)\n" - " --test do everything except actually updating the hardware\n" - " clock or anything else\n" - " -D | --debug debug mode\n" - "\n" - ),RTC_DEV); + " --directisa access the ISA bus directly instead of %s\n" + " --badyear ignore rtc's year because the bios is broken\n" + " --date specifies the time to which to set the hardware clock\n" + " --epoch=year specifies the year which is the beginning of the \n" + " hardware clock's epoch value\n" + " --noadjfile do not access /etc/adjtime. Requires the use of\n" + " either --utc or --localtime\n" + " --adjfile=path specifies the path to the adjust file (default is\n" + " /etc/adjtime)\n" + " --test do everything except actually updating the hardware\n" + " clock or anything else\n" + " -D | --debug debug mode\n" "\n"), RTC_DEV); #ifdef __alpha__ - fprintf(usageto, _( - " -J|--jensen, -A|--arc, -S|--srm, -F|--funky-toy\n" - " tell hwclock the type of alpha you have (see hwclock(8))\n" - "\n" - ) ); + fprintf(usageto, _(" -J|--jensen, -A|--arc, -S|--srm, -F|--funky-toy\n" + " tell hwclock the type of alpha you have (see hwclock(8))\n" + "\n")); #endif - fflush(stdout); - if (fmt) { - usageto = stderr; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } + fflush(stdout); + if (fmt) { + usageto = stderr; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } - hwclock_exit(fmt ? EX_USAGE : 0); + hwclock_exit(fmt ? EX_USAGE : 0); } static const struct option longopts[] = { - { "adjust", 0, 0, 'a' }, - { "help", 0, 0, 'h' }, - { "show", 0, 0, 'r' }, - { "hctosys", 0, 0, 's' }, - { "utc", 0, 0, 'u' }, - { "version", 0, 0, 'v' }, - { "systohc", 0, 0, 'w' }, - { "debug", 0, 0, 'D' }, + {"adjust", 0, 0, 'a'}, + {"help", 0, 0, 'h'}, + {"show", 0, 0, 'r'}, + {"hctosys", 0, 0, 's'}, + {"utc", 0, 0, 'u'}, + {"version", 0, 0, 'v'}, + {"systohc", 0, 0, 'w'}, + {"debug", 0, 0, 'D'}, #ifdef __alpha__ - { "ARC", 0, 0, 'A' }, - { "arc", 0, 0, 'A' }, - { "Jensen", 0, 0, 'J' }, - { "jensen", 0, 0, 'J' }, - { "SRM", 0, 0, 'S' }, - { "srm", 0, 0, 'S' }, - { "funky-toy", 0, 0, 'F'}, + {"ARC", 0, 0, 'A'}, + {"arc", 0, 0, 'A'}, + {"Jensen", 0, 0, 'J'}, + {"jensen", 0, 0, 'J'}, + {"SRM", 0, 0, 'S'}, + {"srm", 0, 0, 'S'}, + {"funky-toy", 0, 0, 'F'}, #endif - { "set", 0, 0, 128 }, + {"set", 0, 0, 128}, #ifdef __linux__ - { "getepoch", 0, 0, 129 }, - { "setepoch", 0, 0, 130 }, + {"getepoch", 0, 0, 129}, + {"setepoch", 0, 0, 130}, #endif - { "noadjfile", 0, 0, 131 }, - { "localtime", 0, 0, 132 }, - { "badyear", 0, 0, 133 }, - { "directisa", 0, 0, 134 }, - { "test", 0, 0, 135 }, - { "date", 1, 0, 136 }, - { "epoch", 1, 0, 137 }, + {"noadjfile", 0, 0, 131}, + {"localtime", 0, 0, 132}, + {"badyear", 0, 0, 133}, + {"directisa", 0, 0, 134}, + {"test", 0, 0, 135}, + {"date", 1, 0, 136}, + {"epoch", 1, 0, 137}, #ifdef __linux__ - { "rtc", 1, 0, 'f' }, + {"rtc", 1, 0, 'f'}, #endif - { "adjfile", 1, 0, 138 }, - { "systz", 0, 0, 139 }, - { "predict-hc", 0, 0, 140 }, - { NULL, 0, 0, 0 } + {"adjfile", 1, 0, 138}, + {"systz", 0, 0, 139}, + {"predict-hc", 0, 0, 140}, + {NULL, 0, 0, 0} }; /* @@ -1442,20 +1467,22 @@ static const struct option longopts[] = { * 0: OK (or not) * 1: failure */ -int -main(int argc, char **argv) { - +int main(int argc, char **argv) +{ struct timeval startup_time; - /* The time we started up, in seconds into the epoch, including - fractions. */ - time_t set_time = 0; /* Time to which user said to set Hardware Clock */ + /* + * The time we started up, in seconds into the epoch, including + * fractions. + */ + time_t set_time = 0; /* Time to which user said to set Hardware Clock */ - bool permitted; /* User is permitted to do the function */ + bool permitted; /* User is permitted to do the function */ int rc, c; /* Variables set by various options; show may also be set later */ /* The options debug, badyear and epoch_option are global */ - bool show, set, systohc, hctosys, systz, adjust, getepoch, setepoch, predict; + bool show, set, systohc, hctosys, systz, adjust, getepoch, setepoch, + predict; bool utc, testing, local_opt, noadjfile, directisa; char *date_opt; #ifdef __alpha__ @@ -1468,32 +1495,37 @@ main(int argc, char **argv) { hwaudit_fd = audit_open(); if (hwaudit_fd < 0 && !(errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) { - /* You get these error codes only when the kernel doesn't have - * audit compiled in. */ + /* + * You get these error codes only when the kernel doesn't + * have audit compiled in. + */ fprintf(stderr, _("%s: Unable to connect to audit system\n"), - MYNAME); + MYNAME); return EX_NOPERM; } #endif setlocale(LC_ALL, ""); #ifdef LC_NUMERIC - /* We need LC_CTYPE and LC_TIME and LC_MESSAGES, but must avoid - LC_NUMERIC since it gives problems when we write to /etc/adjtime. - - gqueri@mail.dotcom.fr */ + /* + * We need LC_CTYPE and LC_TIME and LC_MESSAGES, but must avoid + * LC_NUMERIC since it gives problems when we write to /etc/adjtime. + * - gqueri@mail.dotcom.fr + */ setlocale(LC_NUMERIC, "C"); #endif bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); /* Set option defaults */ - show = set = systohc = hctosys = systz = adjust = noadjfile = predict = FALSE; + show = set = systohc = hctosys = systz = adjust = noadjfile = predict = + FALSE; getepoch = setepoch = utc = local_opt = testing = debug = FALSE; #ifdef __alpha__ ARCconsole = Jensen = SRM = funky_toy = directisa = badyear = FALSE; #endif date_opt = NULL; - while ((c = getopt_long (argc, argv, "?hvVDarsuwAJSFf:", longopts, NULL)) + while ((c = getopt_long(argc, argv, "?hvVDarsuwAJSFf:", longopts, NULL)) != -1) { switch (c) { case 'D': @@ -1543,7 +1575,7 @@ main(int argc, char **argv) { noadjfile = TRUE; break; case 132: - local_opt = TRUE; /* --localtime */ + local_opt = TRUE; /* --localtime */ break; case 133: badyear = TRUE; @@ -1552,33 +1584,33 @@ main(int argc, char **argv) { directisa = TRUE; break; case 135: - testing = TRUE; /* --test */ + testing = TRUE; /* --test */ break; case 136: - date_opt = optarg; /* --date */ + date_opt = optarg; /* --date */ break; case 137: epoch_option = atoi(optarg); /* --epoch */ break; case 138: - adj_file_name = optarg; /* --adjfile */ + adj_file_name = optarg; /* --adjfile */ break; case 139: - systz = TRUE; /* --systz */ + systz = TRUE; /* --systz */ break; case 140: - predict = TRUE; /* --predict-hc */ + predict = TRUE; /* --predict-hc */ break; #ifdef __linux__ case 'f': - rtc_dev_name = optarg; /* --rtc */ + rtc_dev_name = optarg; /* --rtc */ break; #endif - case 'v': /* --version */ + case 'v': /* --version */ case 'V': out_version(); return 0; - case 'h': /* --help */ + case 'h': /* --help */ case '?': default: usage(NULL); @@ -1591,19 +1623,18 @@ main(int argc, char **argv) { #ifdef HAVE_LIBAUDIT if (testing != TRUE) { if (adjust == TRUE || hctosys == TRUE || systohc == TRUE || - set == TRUE || setepoch == TRUE) { + set == TRUE || setepoch == TRUE) { hwaudit_on = TRUE; } } #endif if (argc > 0) { usage(_("%s takes no non-option arguments. " - "You supplied %d.\n"), - MYNAME, argc); + "You supplied %d.\n"), MYNAME, argc); } if (show + set + systohc + hctosys + systz + adjust + getepoch - + setepoch + predict > 1){ + + setepoch + predict > 1) { fprintf(stderr, _("You have specified multiple functions.\n" "You can only perform one function " "at a time.\n")); @@ -1638,7 +1669,6 @@ main(int argc, char **argv) { "either --utc or --localtime\n"), MYNAME); hwclock_exit(EX_USAGE); } - #ifdef __alpha__ set_cmos_epoch(ARCconsole, SRM); set_cmos_access(Jensen, funky_toy); @@ -1656,8 +1686,7 @@ main(int argc, char **argv) { if (!(show | set | systohc | hctosys | systz | adjust | getepoch | setepoch | predict)) - show = 1; /* default to show */ - + show = 1; /* default to show */ if (getuid() == 0) permitted = TRUE; @@ -1710,15 +1739,15 @@ main(int argc, char **argv) { } rc = manipulate_clock(show, adjust, noadjfile, set, set_time, - hctosys, systohc, systz, startup_time, utc, - local_opt, testing, predict); + hctosys, systohc, systz, startup_time, utc, + local_opt, testing, predict); hwclock_exit(rc); - return rc; /* Not reached */ + return rc; /* Not reached */ } /* A single routine for greater uniformity */ -void -outsyserr(char *msg, ...) { +void outsyserr(char *msg, ...) +{ va_list args; int errsv = errno; @@ -1726,144 +1755,130 @@ outsyserr(char *msg, ...) { va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); - fprintf(stderr, ", errno=%d: %s.\n", - errsv, strerror(errsv)); + fprintf(stderr, ", errno=%d: %s.\n", errsv, strerror(errsv)); } - #ifdef HAVE_LIBAUDIT -void -hwaudit_exit(int status) +void hwaudit_exit(int status) { if (hwaudit_on) { audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG, - "changing system time", NULL, NULL, NULL, status ? 0 : 1); + "changing system time", NULL, NULL, NULL, + status ? 0 : 1); close(hwaudit_fd); } exit(status); } #endif -/**************************************************************************** - - History of this program: - - 98.08.12 BJH Version 2.4 - - Don't use century byte from Hardware Clock. Add comments telling why. - - - 98.06.20 BJH Version 2.3. - - Make --hctosys set the kernel timezone from TZ environment variable - and/or /usr/lib/zoneinfo. From Klaus Ripke (klaus@ripke.com). - - 98.03.05 BJH. Version 2.2. - - Add --getepoch and --setepoch. - - Fix some word length things so it works on Alpha. - - Make it work when /dev/rtc doesn't have the interrupt functions. - In this case, busywait for the top of a second instead of blocking and - waiting for the update complete interrupt. - - Fix a bunch of bugs too numerous to mention. - - 97.06.01: BJH. Version 2.1. Read and write the century byte (Byte - 50) of the ISA Hardware Clock when using direct ISA I/O. Problem - discovered by job (jei@iclnl.icl.nl). - - Use the rtc clock access method in preference to the KDGHWCLK method. - Problem discovered by Andreas Schwab . - - November 1996: Version 2.0.1. Modifications by Nicolai Langfeldt - (janl@math.uio.no) to make it compile on linux 1.2 machines as well - as more recent versions of the kernel. Introduced the NO_CLOCK - access method and wrote feature test code to detect absense of rtc - headers. - - -************************************************************************** - Maintenance notes - - To compile this, you must use GNU compiler optimization (-O option) - in order to make the "extern inline" functions from asm/io.h (inb(), - etc.) compile. If you don't optimize, which means the compiler - will generate no inline functions, the references to these functions - in this program will be compiled as external references. Since you - probably won't be linking with any functions by these names, you will - have unresolved external references when you link. - - The program is designed to run setuid superuser, since we need to be - able to do direct I/O. (More to the point: we need permission to - execute the iopl() system call). (However, if you use one of the - methods other than direct ISA I/O to access the clock, no setuid is - required). - - Here's some info on how we must deal with the time that elapses while - this program runs: There are two major delays as we run: - - 1) Waiting up to 1 second for a transition of the Hardware Clock so - we are synchronized to the Hardware Clock. - - 2) Running the "date" program to interpret the value of our --date - option. - - Reading the /etc/adjtime file is the next biggest source of delay and - uncertainty. - - The user wants to know what time it was at the moment he invoked us, - not some arbitrary time later. And in setting the clock, he is - giving us the time at the moment we are invoked, so if we set the - clock some time later, we have to add some time to that. - - So we check the system time as soon as we start up, then run "date" - and do file I/O if necessary, then wait to synchronize with a - Hardware Clock edge, then check the system time again to see how - much time we spent. We immediately read the clock then and (if - appropriate) report that time, and additionally, the delay we measured. - - If we're setting the clock to a time given by the user, we wait some - more so that the total delay is an integral number of seconds, then - set the Hardware Clock to the time the user requested plus that - integral number of seconds. N.B. The Hardware Clock can only be set - in integral seconds. - - If we're setting the clock to the system clock value, we wait for - the system clock to reach the top of a second, and then set the - Hardware Clock to the system clock's value. - - Here's an interesting point about setting the Hardware Clock: On my - machine, when you set it, it sets to that precise time. But one can - imagine another clock whose update oscillator marches on a steady one - second period, so updating the clock between any two oscillator ticks - is the same as updating it right at the earlier tick. To avoid any - complications that might cause, we set the clock as soon as possible - after an oscillator tick. - - - About synchronizing to the Hardware Clock when reading the time: The - precision of the Hardware Clock counters themselves is one second. - You can't read the counters and find out that is 12:01:02.5. But if - you consider the location in time of the counter's ticks as part of - its value, then its precision is as infinite as time is continuous! - What I'm saying is this: To find out the _exact_ time in the - hardware clock, we wait until the next clock tick (the next time the - second counter changes) and measure how long we had to wait. We - then read the value of the clock counters and subtract the wait time - and we know precisely what time it was when we set out to query the - time. - - hwclock uses this method, and considers the Hardware Clock to have - infinite precision. - - - Enhancements needed: - - - When waiting for whole second boundary in set_hardware_clock_exact, - fail if we miss the goal by more than .1 second, as could happen if - we get pre-empted (by the kernel dispatcher). - -****************************************************************************/ - +/* + * History of this program: + * + * 98.08.12 BJH Version 2.4 + * + * Don't use century byte from Hardware Clock. Add comments telling why. + * + * 98.06.20 BJH Version 2.3. + * + * Make --hctosys set the kernel timezone from TZ environment variable + * and/or /usr/lib/zoneinfo. From Klaus Ripke (klaus@ripke.com). + * + * 98.03.05 BJH. Version 2.2. + * + * Add --getepoch and --setepoch. + * + * Fix some word length things so it works on Alpha. + * + * Make it work when /dev/rtc doesn't have the interrupt functions. In this + * case, busywait for the top of a second instead of blocking and waiting + * for the update complete interrupt. + * + * Fix a bunch of bugs too numerous to mention. + * + * 97.06.01: BJH. Version 2.1. Read and write the century byte (Byte 50) of + * the ISA Hardware Clock when using direct ISA I/O. Problem discovered by + * job (jei@iclnl.icl.nl). + * + * Use the rtc clock access method in preference to the KDGHWCLK method. + * Problem discovered by Andreas Schwab . + * + * November 1996: Version 2.0.1. Modifications by Nicolai Langfeldt + * (janl@math.uio.no) to make it compile on linux 1.2 machines as well as + * more recent versions of the kernel. Introduced the NO_CLOCK access method + * and wrote feature test code to detect absense of rtc headers. + * + *************************************************************************** + * Maintenance notes + * + * To compile this, you must use GNU compiler optimization (-O option) in + * order to make the "extern inline" functions from asm/io.h (inb(), etc.) + * compile. If you don't optimize, which means the compiler will generate no + * inline functions, the references to these functions in this program will + * be compiled as external references. Since you probably won't be linking + * with any functions by these names, you will have unresolved external + * references when you link. + * + * The program is designed to run setuid superuser, since we need to be able + * to do direct I/O. (More to the point: we need permission to execute the + * iopl() system call). (However, if you use one of the methods other than + * direct ISA I/O to access the clock, no setuid is required). + * + * Here's some info on how we must deal with the time that elapses while + * this program runs: There are two major delays as we run: + * + * 1) Waiting up to 1 second for a transition of the Hardware Clock so + * we are synchronized to the Hardware Clock. + * 2) Running the "date" program to interpret the value of our --date + * option. + * + * Reading the /etc/adjtime file is the next biggest source of delay and + * uncertainty. + * + * The user wants to know what time it was at the moment he invoked us, not + * some arbitrary time later. And in setting the clock, he is giving us the + * time at the moment we are invoked, so if we set the clock some time + * later, we have to add some time to that. + * + * So we check the system time as soon as we start up, then run "date" and + * do file I/O if necessary, then wait to synchronize with a Hardware Clock + * edge, then check the system time again to see how much time we spent. We + * immediately read the clock then and (if appropriate) report that time, + * and additionally, the delay we measured. + * + * If we're setting the clock to a time given by the user, we wait some more + * so that the total delay is an integral number of seconds, then set the + * Hardware Clock to the time the user requested plus that integral number + * of seconds. N.B. The Hardware Clock can only be set in integral seconds. + * + * If we're setting the clock to the system clock value, we wait for the + * system clock to reach the top of a second, and then set the Hardware + * Clock to the system clock's value. + * + * Here's an interesting point about setting the Hardware Clock: On my + * machine, when you set it, it sets to that precise time. But one can + * imagine another clock whose update oscillator marches on a steady one + * second period, so updating the clock between any two oscillator ticks is + * the same as updating it right at the earlier tick. To avoid any + * complications that might cause, we set the clock as soon as possible + * after an oscillator tick. + * + * About synchronizing to the Hardware Clock when reading the time: The + * precision of the Hardware Clock counters themselves is one second. You + * can't read the counters and find out that is 12:01:02.5. But if you + * consider the location in time of the counter's ticks as part of its + * value, then its precision is as infinite as time is continuous! What I'm + * saying is this: To find out the _exact_ time in the hardware clock, we + * wait until the next clock tick (the next time the second counter changes) + * and measure how long we had to wait. We then read the value of the clock + * counters and subtract the wait time and we know precisely what time it + * was when we set out to query the time. + * + * hwclock uses this method, and considers the Hardware Clock to have + * infinite precision. + * + * TODO: Enhancements needed: + * + * - When waiting for whole second boundary in set_hardware_clock_exact, + * fail if we miss the goal by more than .1 second, as could happen if we + * get pre-empted (by the kernel dispatcher). + */ diff --git a/hwclock/kd.c b/hwclock/kd.c index 66ff579bb..f4957ac64 100644 --- a/hwclock/kd.c +++ b/hwclock/kd.c @@ -1,19 +1,21 @@ -/* kd.c - KDGHWCLK stuff, possibly m68k only - deprecated */ +/* + * kd.c - KDGHWCLK stuff, possibly m68k only, likely to be deprecated + */ #include "clock.h" #ifdef __m68k__ -#include /* for close() */ -#include /* for O_RDONLY */ -#include -#include +# include /* for close() */ +# include /* for O_RDONLY */ +# include +# include -#include "nls.h" -#include "usleep.h" +# include "nls.h" +# include "usleep.h" /* Get defines for KDGHWCLK and KDSHWCLK (m68k) */ -#include +# include /* Even on m68k, if KDGHWCLK (antique) is not defined, don't build this */ @@ -21,124 +23,126 @@ #if !defined(__m68k__) || !defined(KDGHWCLK) -struct clock_ops * -probe_for_kd_clock() { +struct clock_ops *probe_for_kd_clock() +{ return NULL; } -#else /* __m68k__ && KDGHWCLK */ +#else /* __m68k__ && KDGHWCLK */ -static int con_fd = -1; /* opened by probe_for_kd_clock() */ - /* never closed */ +/* Opened by probe_for_kd_clock(), and never closed. */ +static int con_fd = -1; static char *con_fd_filename; /* usually "/dev/tty1" */ -static int -synchronize_to_clock_tick_kd(void) { -/*---------------------------------------------------------------------------- - Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until - we see it. ------------------------------------------------------------------------------*/ +/* + * Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until + * we see it. + */ +static int synchronize_to_clock_tick_kd(void) +{ + /* The time when we were called (and started waiting) */ + struct hwclk_time start_time, nowtime; + struct timeval begin, now; - /* The time when we were called (and started waiting) */ - struct hwclk_time start_time, nowtime; - struct timeval begin, now; + if (debug) + printf(_("Waiting in loop for time from KDGHWCLK to change\n")); - if (debug) - printf(_("Waiting in loop for time from KDGHWCLK to change\n")); + if (ioctl(con_fd, KDGHWCLK, &start_time) == -1) { + outsyserr(_("KDGHWCLK ioctl to read time failed")); + return 3; + } - if (ioctl(con_fd, KDGHWCLK, &start_time) == -1) { - outsyserr(_("KDGHWCLK ioctl to read time failed")); - return 3; - } + /* + * Wait for change. Should be within a second, but in case something + * weird happens, we have a time limit (1.5s) on this loop to reduce + * the impact of this failure. + */ + gettimeofday(&begin, NULL); + do { + /* + * Added by Roman Hodek + * + * "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 + * sleep helps." + */ + usleep(1); - /* Wait for change. Should be within a second, but in case something - * weird happens, we have a time limit (1.5s) on this loop to reduce the - * impact of this failure. - */ - gettimeofday(&begin, NULL); - do { - /* Added by Roman Hodek - * "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 sleep helps." - */ - usleep(1); + if (ioctl(con_fd, KDGHWCLK, &nowtime) == -1) { + outsyserr(_ + ("KDGHWCLK ioctl to read time failed in loop")); + return 3; + } + if (start_time.tm_sec != nowtime.tm_sec) + break; + gettimeofday(&now, NULL); + if (time_diff(now, begin) > 1.5) { + fprintf(stderr, + _("Timed out waiting for time change.\n")); + return 2; + } + } while (1); - if (ioctl(con_fd, KDGHWCLK, &nowtime) == -1) { - outsyserr(_("KDGHWCLK ioctl to read time failed in loop")); - return 3; - } - if (start_time.tm_sec != nowtime.tm_sec) - break; - gettimeofday(&now, NULL); - if (time_diff(now, begin) > 1.5) { - fprintf(stderr, _("Timed out waiting for time change.\n")); - return 2; - } - } while(1); - - return 0; + return 0; } +/* + * Read the hardware clock and return the current time via argument. + * Use ioctls to /dev/tty1 on what we assume is an m68k machine. + * + * Note that we don't use /dev/console here. That might be a serial console. + */ +static int read_hardware_clock_kd(struct tm *tm) +{ + struct hwclk_time t; -static int -read_hardware_clock_kd(struct tm *tm) { -/*---------------------------------------------------------------------------- - Read the hardware clock and return the current time via - argument. Use ioctls to /dev/tty1 on what we assume is an m68k - machine. + if (ioctl(con_fd, KDGHWCLK, &t) == -1) { + outsyserr(_("ioctl() failed to read time from %s"), + con_fd_filename); + hwclock_exit(EX_IOERR); + } - Note that we don't use /dev/console here. That might be a serial - console. ------------------------------------------------------------------------------*/ - struct hwclk_time t; + tm->tm_sec = t.sec; + tm->tm_min = t.min; + tm->tm_hour = t.hour; + tm->tm_mday = t.day; + tm->tm_mon = t.mon; + tm->tm_year = t.year; + tm->tm_wday = t.wday; + tm->tm_isdst = -1; /* Don't know if it's Daylight Savings Time */ - if (ioctl(con_fd, KDGHWCLK, &t) == -1) { - outsyserr(_("ioctl() failed to read time from %s"), con_fd_filename); - hwclock_exit(EX_IOERR); - } - - tm->tm_sec = t.sec; - tm->tm_min = t.min; - tm->tm_hour = t.hour; - tm->tm_mday = t.day; - tm->tm_mon = t.mon; - tm->tm_year = t.year; - tm->tm_wday = t.wday; - tm->tm_isdst = -1; /* Don't know if it's Daylight Savings Time */ - - return 0; + return 0; } +/* + * Set the Hardware Clock to the time . Use ioctls to + * /dev/tty1 on what we assume is an m68k machine. + * + * Note that we don't use /dev/console here. That might be a serial console. + */ +static int set_hardware_clock_kd(const struct tm *new_broken_time) +{ + struct hwclk_time t; -static int -set_hardware_clock_kd(const struct tm *new_broken_time) { -/*---------------------------------------------------------------------------- - Set the Hardware Clock to the time . Use ioctls to - /dev/tty1 on what we assume is an m68k machine. + t.sec = new_broken_time->tm_sec; + t.min = new_broken_time->tm_min; + t.hour = new_broken_time->tm_hour; + t.day = new_broken_time->tm_mday; + t.mon = new_broken_time->tm_mon; + t.year = new_broken_time->tm_year; + t.wday = new_broken_time->tm_wday; - Note that we don't use /dev/console here. That might be a serial console. -----------------------------------------------------------------------------*/ - struct hwclk_time t; - - t.sec = new_broken_time->tm_sec; - t.min = new_broken_time->tm_min; - t.hour = new_broken_time->tm_hour; - t.day = new_broken_time->tm_mday; - t.mon = new_broken_time->tm_mon; - t.year = new_broken_time->tm_year; - t.wday = new_broken_time->tm_wday; - - if (ioctl(con_fd, KDSHWCLK, &t ) == -1) { - outsyserr(_("ioctl KDSHWCLK failed")); - hwclock_exit(1); - } - return 0; + if (ioctl(con_fd, KDSHWCLK, &t) == -1) { + outsyserr(_("ioctl KDSHWCLK failed")); + hwclock_exit(1); + } + return 0; } -static int -get_permissions_kd(void) { - return 0; +static int get_permissions_kd(void) +{ + return 0; } static struct clock_ops kd = { @@ -150,8 +154,8 @@ static struct clock_ops kd = { }; /* return &kd if KDGHWCLK works, NULL otherwise */ -struct clock_ops * -probe_for_kd_clock() { +struct clock_ops *probe_for_kd_clock() +{ struct clock_ops *ret = NULL; struct hwclk_time t; @@ -176,4 +180,4 @@ probe_for_kd_clock() { } return ret; } -#endif /* __m68k__ && KDGHWCLK */ +#endif /* __m68k__ && KDGHWCLK */ diff --git a/hwclock/rtc.c b/hwclock/rtc.c index 2e053856a..21c7d746d 100644 --- a/hwclock/rtc.c +++ b/hwclock/rtc.c @@ -1,4 +1,6 @@ -/* rtc.c - Use /dev/rtc for clock access */ +/* + * rtc.c - Use /dev/rtc for clock access + */ #include /* for close() */ #include /* for O_RDONLY */ #include @@ -12,77 +14,83 @@ /* * Get defines for rtc stuff. * - * Getting the rtc defines is nontrivial. - * The obvious way is by including - * but that again includes which again includes ... - * and on sparc and alpha this gives compilation errors for - * many kernel versions. So, we give the defines ourselves here. - * Moreover, some Sparc person decided to be incompatible, and - * used a struct rtc_time different from that used in mc146818rtc.h. + * Getting the rtc defines is nontrivial. The obvious way is by including + * but that again includes which again + * includes ... and on sparc and alpha this gives compilation errors for + * many kernel versions. So, we give the defines ourselves here. Moreover, + * some Sparc person decided to be incompatible, and used a struct rtc_time + * different from that used in mc146818rtc.h. */ -/* On Sparcs, there is a that defines different ioctls - (that are required on my machine). However, this include file - does not exist on other architectures. */ +/* + * On Sparcs, there is a that defines different ioctls (that are + * required on my machine). However, this include file does not exist on + * other architectures. + */ /* One might do: #ifdef __sparc__ -#include +# include #endif */ /* The following is roughly equivalent */ struct sparc_rtc_time { - int sec; /* Seconds (0-59) */ - int min; /* Minutes (0-59) */ - int hour; /* Hour (0-23) */ - int dow; /* Day of the week (1-7) */ - int dom; /* Day of the month (1-31) */ - int month; /* Month of year (1-12) */ - int year; /* Year (0-99) */ + int sec; /* Seconds 0-59 */ + int min; /* Minutes 0-59 */ + int hour; /* Hour 0-23 */ + int dow; /* Day of the week 1-7 */ + int dom; /* Day of the month 1-31 */ + int month; /* Month of year 1-12 */ + int year; /* Year 0-99 */ }; #define RTCGET _IOR('p', 20, struct sparc_rtc_time) #define RTCSET _IOW('p', 21, struct sparc_rtc_time) - /* non-sparc stuff */ #if 0 -#include -/* Check if the /dev/rtc interface is available in this version of - the system headers. 131072 is linux 2.0.0. */ -#if LINUX_VERSION_CODE >= 131072 -#include -#endif +# include +/* + * Check if the /dev/rtc interface is available in this version of the + * system headers. 131072 is linux 2.0.0. + */ +# if LINUX_VERSION_CODE >= 131072 +# include +# endif #endif -/* struct rtc_time is present since 1.3.99 */ -/* Earlier (since 1.3.89), a struct tm was used. */ +/* + * struct rtc_time is present since 1.3.99. + * Earlier (since 1.3.89), a struct tm was used. + */ struct linux_rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; }; /* RTC_RD_TIME etc have this definition since 1.99.9 (pre2.0-9) */ #ifndef RTC_RD_TIME -#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) -#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* Update int. enable off */ -#endif -/* RTC_EPOCH_READ and RTC_EPOCH_SET are present since 2.0.34 and 2.1.89 */ -#ifndef RTC_EPOCH_READ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ +# define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) +# define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) +# define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ +# define RTC_UIE_OFF _IO('p', 0x04) /* Update int. enable off */ #endif -/* /dev/rtc is conventionally chardev 10/135 +/* RTC_EPOCH_READ and RTC_EPOCH_SET are present since 2.0.34 and 2.1.89 */ +#ifndef RTC_EPOCH_READ +# define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +# define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ +#endif + +/* + * /dev/rtc is conventionally chardev 10/135 * ia64 uses /dev/efirtc, chardev 10/136 * devfs (obsolete) used /dev/misc/... for miscdev * new RTC framework + udev uses dynamic major and /dev/rtc0.../dev/rtcN @@ -94,15 +102,15 @@ char *rtc_dev_name; static int rtc_dev_fd = -1; -static void -close_rtc(void) { +static void close_rtc(void) +{ if (rtc_dev_fd != -1) close(rtc_dev_fd); rtc_dev_fd = -1; } -static int -open_rtc(void) { +static int open_rtc(void) +{ char *fls[] = { #ifdef __ia64__ "/dev/efirtc", @@ -122,10 +130,11 @@ open_rtc(void) { if (rtc_dev_name) rtc_dev_fd = open(rtc_dev_name, O_RDONLY); else { - for (p=fls; *p; ++p) { + for (p = fls; *p; ++p) { rtc_dev_fd = open(*p, O_RDONLY); - if (rtc_dev_fd < 0 && (errno == ENOENT || errno == ENODEV)) + if (rtc_dev_fd < 0 + && (errno == ENOENT || errno == ENODEV)) continue; rtc_dev_name = *p; break; @@ -139,8 +148,8 @@ open_rtc(void) { return rtc_dev_fd; } -static int -open_rtc_or_exit(void) { +static int open_rtc_or_exit(void) +{ int rtc_fd = open_rtc(); if (rtc_fd < 0) { @@ -150,8 +159,8 @@ open_rtc_or_exit(void) { return rtc_fd; } -static int -do_rtc_read_ioctl(int rtc_fd, struct tm *tm) { +static int do_rtc_read_ioctl(int rtc_fd, struct tm *tm) +{ int rc = -1; char *ioctlname; @@ -169,7 +178,7 @@ do_rtc_read_ioctl(int rtc_fd, struct tm *tm) { tm->tm_mon = stm.month - 1; tm->tm_year = stm.year - 1900; tm->tm_wday = stm.dow - 1; - tm->tm_yday = -1; /* day in the year */ + tm->tm_yday = -1; /* day in the year */ } #endif if (rc == -1) { /* no sparc, or RTCGET failed */ @@ -183,134 +192,153 @@ do_rtc_read_ioctl(int rtc_fd, struct tm *tm) { return -1; } - tm->tm_isdst = -1; /* don't know whether it's dst */ + tm->tm_isdst = -1; /* don't know whether it's dst */ return 0; } -static int -busywait_for_rtc_clock_tick(const int rtc_fd) { -/*---------------------------------------------------------------------------- - Wait for the top of a clock tick by reading /dev/rtc in a busy loop until - we see it. ------------------------------------------------------------------------------*/ - struct tm start_time; - /* The time when we were called (and started waiting) */ - struct tm nowtime; - int rc; - struct timeval begin, now; +/* + * Wait for the top of a clock tick by reading /dev/rtc in a busy loop until + * we see it. + */ +static int busywait_for_rtc_clock_tick(const int rtc_fd) +{ + struct tm start_time; + /* The time when we were called (and started waiting) */ + struct tm nowtime; + int rc; + struct timeval begin, now; - if (debug) - printf(_("Waiting in loop for time from %s to change\n"), - rtc_dev_name); + if (debug) + printf(_("Waiting in loop for time from %s to change\n"), + rtc_dev_name); - rc = do_rtc_read_ioctl(rtc_fd, &start_time); - if (rc) - return 1; + rc = do_rtc_read_ioctl(rtc_fd, &start_time); + if (rc) + return 1; - /* Wait for change. Should be within a second, but in case something - * weird happens, we have a time limit (1.5s) on this loop to reduce the - * impact of this failure. - */ - gettimeofday(&begin, NULL); - do { - rc = do_rtc_read_ioctl(rtc_fd, &nowtime); - if (rc || start_time.tm_sec != nowtime.tm_sec) - break; - gettimeofday(&now, NULL); - if (time_diff(now, begin) > 1.5) { - fprintf(stderr, _("Timed out waiting for time change.\n")); - return 2; - } - } while(1); + /* + * Wait for change. Should be within a second, but in case + * something weird happens, we have a time limit (1.5s) on this loop + * to reduce the impact of this failure. + */ + gettimeofday(&begin, NULL); + do { + rc = do_rtc_read_ioctl(rtc_fd, &nowtime); + if (rc || start_time.tm_sec != nowtime.tm_sec) + break; + gettimeofday(&now, NULL); + if (time_diff(now, begin) > 1.5) { + fprintf(stderr, + _("Timed out waiting for time change.\n")); + return 2; + } + } while (1); - if (rc) - return 3; - return 0; + if (rc) + return 3; + return 0; } -static int -synchronize_to_clock_tick_rtc(void) { -/*---------------------------------------------------------------------------- - Same as synchronize_to_clock_tick(), but just for /dev/rtc. ------------------------------------------------------------------------------*/ -int rtc_fd; /* File descriptor of /dev/rtc */ -int ret; +/* + * Same as synchronize_to_clock_tick(), but just for /dev/rtc. + */ +static int synchronize_to_clock_tick_rtc(void) +{ + int rtc_fd; /* File descriptor of /dev/rtc */ + int ret; - rtc_fd = open_rtc(); - if (rtc_fd == -1) { - outsyserr(_("open() of %s failed"), rtc_dev_name); - ret = 1; - } else { - int rc; /* Return code from ioctl */ - /* Turn on update interrupts (one per second) */ + rtc_fd = open_rtc(); + if (rtc_fd == -1) { + outsyserr(_("open() of %s failed"), rtc_dev_name); + ret = 1; + } else { + int rc; /* Return code from ioctl */ + /* Turn on update interrupts (one per second) */ #if defined(__alpha__) || defined(__sparc__) - /* Not all alpha kernels reject RTC_UIE_ON, but probably they should. */ - rc = -1; - errno = EINVAL; + /* + * Not all alpha kernels reject RTC_UIE_ON, but probably + * they should. + */ + rc = -1; + errno = EINVAL; #else - rc = ioctl(rtc_fd, RTC_UIE_ON, 0); + rc = ioctl(rtc_fd, RTC_UIE_ON, 0); #endif - if (rc == -1 && (errno == ENOTTY || errno == EINVAL)) { - /* This rtc device doesn't have interrupt functions. This is typical - on an Alpha, where the Hardware Clock interrupts are used by the - kernel for the system clock, so aren't at the user's disposal. - */ - if (debug) - printf(_("%s does not have interrupt functions. "), - rtc_dev_name); - ret = busywait_for_rtc_clock_tick(rtc_fd); - } else if (rc == 0) { + if (rc == -1 && (errno == ENOTTY || errno == EINVAL)) { + /* + * This rtc device doesn't have interrupt functions. + * This is typical on an Alpha, where the Hardware + * Clock interrupts are used by the kernel for the + * system clock, so aren't at the user's disposal. + */ + if (debug) + printf(_ + ("%s does not have interrupt functions. "), + rtc_dev_name); + ret = busywait_for_rtc_clock_tick(rtc_fd); + } else if (rc == 0) { #ifdef Wait_until_update_interrupt - unsigned long dummy; + unsigned long dummy; - /* this blocks until the next update interrupt */ - rc = read(rtc_fd, &dummy, sizeof(dummy)); - ret = 1; - if (rc == -1) - outsyserr(_("read() to %s to wait for clock tick failed"), - rtc_dev_name); - else - ret = 0; + /* this blocks until the next update interrupt */ + rc = read(rtc_fd, &dummy, sizeof(dummy)); + ret = 1; + if (rc == -1) + outsyserr(_ + ("read() to %s to wait for clock tick failed"), + rtc_dev_name); + else + ret = 0; #else - /* Just reading rtc_fd fails on broken hardware: no update - interrupt comes and a bootscript with a hwclock call hangs */ - fd_set rfds; - struct timeval tv; + /* + * Just reading rtc_fd fails on broken hardware: no + * update interrupt comes and a bootscript with a + * hwclock call hangs + */ + fd_set rfds; + struct timeval tv; - /* Wait up to five seconds for the next update interrupt */ - FD_ZERO(&rfds); - FD_SET(rtc_fd, &rfds); - tv.tv_sec = 5; - tv.tv_usec = 0; - rc = select(rtc_fd + 1, &rfds, NULL, NULL, &tv); - ret = 1; - if (rc == -1) - outsyserr(_("select() to %s to wait for clock tick failed"), - rtc_dev_name); - else if (rc == 0) - fprintf(stderr, _("select() to %s to wait for clock tick timed out\n"), - rtc_dev_name); - else - ret = 0; + /* + * Wait up to five seconds for the next update + * interrupt + */ + FD_ZERO(&rfds); + FD_SET(rtc_fd, &rfds); + tv.tv_sec = 5; + tv.tv_usec = 0; + rc = select(rtc_fd + 1, &rfds, NULL, NULL, &tv); + ret = 1; + if (rc == -1) + outsyserr(_ + ("select() to %s to wait for clock tick failed"), + rtc_dev_name); + else if (rc == 0) + fprintf(stderr, + _ + ("select() to %s to wait for clock tick timed out\n"), + rtc_dev_name); + else + ret = 0; #endif - /* Turn off update interrupts */ - rc = ioctl(rtc_fd, RTC_UIE_OFF, 0); - if (rc == -1) - outsyserr(_("ioctl() to %s to turn off update interrupts failed"), - rtc_dev_name); - } else { - outsyserr(_("ioctl() to %s to turn on update interrupts " - "failed unexpectedly"), rtc_dev_name); - ret = 1; - } - } - return ret; + /* Turn off update interrupts */ + rc = ioctl(rtc_fd, RTC_UIE_OFF, 0); + if (rc == -1) + outsyserr(_ + ("ioctl() to %s to turn off update interrupts failed"), + rtc_dev_name); + } else { + outsyserr(_ + ("ioctl() to %s to turn on update interrupts " + "failed unexpectedly"), rtc_dev_name); + ret = 1; + } + } + return ret; } - -static int -read_hardware_clock_rtc(struct tm *tm) { +static int read_hardware_clock_rtc(struct tm *tm) +{ int rtc_fd, rc; rtc_fd = open_rtc_or_exit(); @@ -321,13 +349,12 @@ read_hardware_clock_rtc(struct tm *tm) { return rc; } - -static int -set_hardware_clock_rtc(const struct tm *new_broken_time) { -/*------------------------------------------------------------------------- - Set the Hardware Clock to the broken down time . - Use ioctls to "rtc" device /dev/rtc. - -------------------------------------------------------------------------*/ +/* + * Set the Hardware Clock to the broken down time . Use + * ioctls to "rtc" device /dev/rtc. + */ +static int set_hardware_clock_rtc(const struct tm *new_broken_time) +{ int rc = -1; int rtc_fd; char *ioctlname; @@ -368,9 +395,8 @@ set_hardware_clock_rtc(const struct tm *new_broken_time) { return 0; } - -static int -get_permissions_rtc(void) { +static int get_permissions_rtc(void) +{ return 0; } @@ -383,8 +409,8 @@ static struct clock_ops rtc = { }; /* return &rtc if /dev/rtc can be opened, NULL otherwise */ -struct clock_ops * -probe_for_rtc_clock(){ +struct clock_ops *probe_for_rtc_clock() +{ int rtc_fd = open_rtc(); if (rtc_fd >= 0) return &rtc; @@ -393,85 +419,91 @@ probe_for_rtc_clock(){ return NULL; } +/* + * Get the Hardware Clock epoch setting from the kernel. + */ +int get_epoch_rtc(unsigned long *epoch_p, int silent) +{ + int rtc_fd; + rtc_fd = open_rtc(); + if (rtc_fd < 0) { + if (!silent) { + if (errno == ENOENT) + fprintf(stderr, + _ + ("To manipulate the epoch value in the kernel, we must " + "access the Linux 'rtc' device driver via the device special " + "file %s. This file does not exist on this system.\n"), + rtc_dev_name); + else + outsyserr(_("Unable to open %s"), rtc_dev_name); + } + return 1; + } -int -get_epoch_rtc(unsigned long *epoch_p, int silent) { -/*---------------------------------------------------------------------------- - Get the Hardware Clock epoch setting from the kernel. -----------------------------------------------------------------------------*/ - int rtc_fd; + if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) { + if (!silent) + outsyserr(_("ioctl(RTC_EPOCH_READ) to %s failed"), + rtc_dev_name); + return 1; + } - rtc_fd = open_rtc(); - if (rtc_fd < 0) { - if (!silent) { - if (errno == ENOENT) - fprintf(stderr, _( - "To manipulate the epoch value in the kernel, we must " - "access the Linux 'rtc' device driver via the device special " - "file %s. This file does not exist on this system.\n"), - rtc_dev_name); - else - outsyserr(_("Unable to open %s"), rtc_dev_name); - } - return 1; - } + if (debug) + printf(_("we have read epoch %ld from %s " + "with RTC_EPOCH_READ ioctl.\n"), *epoch_p, + rtc_dev_name); - if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) { - if (!silent) - outsyserr(_("ioctl(RTC_EPOCH_READ) to %s failed"), rtc_dev_name); - return 1; - } - - if (debug) - printf(_("we have read epoch %ld from %s " - "with RTC_EPOCH_READ ioctl.\n"), *epoch_p, rtc_dev_name); - - return 0; + return 0; } +/* + * Set the Hardware Clock epoch in the kernel. + */ +int set_epoch_rtc(unsigned long epoch) +{ + int rtc_fd; + if (epoch < 1900) { + /* kernel would not accept this epoch value + * + * Bad habit, deciding not to do what the user asks just + * because one believes that the kernel might not like it. + */ + fprintf(stderr, _("The epoch value may not be less than 1900. " + "You requested %ld\n"), epoch); + return 1; + } -int -set_epoch_rtc(unsigned long epoch) { -/*---------------------------------------------------------------------------- - Set the Hardware Clock epoch in the kernel. -----------------------------------------------------------------------------*/ - int rtc_fd; + rtc_fd = open_rtc(); + if (rtc_fd < 0) { + if (errno == ENOENT) + fprintf(stderr, + _ + ("To manipulate the epoch value in the kernel, we must " + "access the Linux 'rtc' device driver via the device special " + "file %s. This file does not exist on this system.\n"), + rtc_dev_name); + else + outsyserr(_("Unable to open %s"), rtc_dev_name); + return 1; + } - if (epoch < 1900) { - /* kernel would not accept this epoch value */ - /* Hmm - bad habit, deciding not to do what the user asks - just because one believes that the kernel might not like it. */ - fprintf(stderr, _("The epoch value may not be less than 1900. " - "You requested %ld\n"), epoch); - return 1; - } + if (debug) + printf(_("setting epoch to %ld " + "with RTC_EPOCH_SET ioctl to %s.\n"), epoch, + rtc_dev_name); - rtc_fd = open_rtc(); - if (rtc_fd < 0) { - if (errno == ENOENT) - fprintf(stderr, _("To manipulate the epoch value in the kernel, we must " - "access the Linux 'rtc' device driver via the device special " - "file %s. This file does not exist on this system.\n"), - rtc_dev_name); - else - outsyserr(_("Unable to open %s"), rtc_dev_name); - return 1; - } + if (ioctl(rtc_fd, RTC_EPOCH_SET, epoch) == -1) { + if (errno == EINVAL) + fprintf(stderr, _("The kernel device driver for %s " + "does not have the RTC_EPOCH_SET ioctl.\n"), + rtc_dev_name); + else + outsyserr(_("ioctl(RTC_EPOCH_SET) to %s failed"), + rtc_dev_name); + return 1; + } - if (debug) - printf(_("setting epoch to %ld " - "with RTC_EPOCH_SET ioctl to %s.\n"), epoch, rtc_dev_name); - - if (ioctl(rtc_fd, RTC_EPOCH_SET, epoch) == -1) { - if (errno == EINVAL) - fprintf(stderr, _("The kernel device driver for %s " - "does not have the RTC_EPOCH_SET ioctl.\n"), rtc_dev_name); - else - outsyserr(_("ioctl(RTC_EPOCH_SET) to %s failed"), rtc_dev_name); - return 1; - } - - return 0; + return 0; }