* Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#)Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.\n\
* Andrew A. Chernov <ache@astral.msk.su> Dec 15 1993
* Fix kernel time value if machine run wall CMOS clock
* (and /etc/wall_cmos_clock file present)
* using zoneinfo rules or direct TZ environment variable set.
* Use Joerg Wunsch idea for seconds accurate offset calculation
* with Garrett Wollman and Bruce Evans fixes.
char storage
[] = _PATH_OFFSET
;
struct timezone tz
, *stz
;
/* Avoid time_t here, can be unsigned long */
long offset
, oldoffset
, utcsec
, localsec
, diff
;
int ch
, init
= -1, verbose
= 0;
while ((ch
= getopt(argc
, argv
, "aiv")) != EOF
)
case 'i': /* initial call, save offset */
case 'a': /* adjustment call, use saved offset */
fprintf(stderr
, "Usage:\n\
\tadjkerntz -i [-v]\t(initial call from /etc/rc)\n\
\tadjkerntz -a [-v]\t(adjustment call from crontab)\n");
if (access(_PATH_CLOCK
, F_OK
))
/* Restore saved offset */
if ((f
= fopen(storage
, "r")) == NULL
) {
if (fscanf(f
, "%ld", &oldoffset
) != 1) {
fprintf(stderr
, "Incorrect offset in %s\n", storage
);
/****** Critical section, do all things as fast as possible ******/
/* get local CMOS clock and possible kernel offset */
if (gettimeofday(&tv
, &tz
)) {
/* get the actual local timezone difference */
local
= *localtime(&tv
.tv_sec
);
utc
= *gmtime(&tv
.tv_sec
);
utc
.tm_isdst
= local
.tm_isdst
; /* Use current timezone for mktime(), */
/* because it assumed local time */
/* calculate local CMOS diff from GMT */
localsec
= mktime(&local
);
if (utcsec
== -1 || localsec
== -1) {
fprintf(stderr
, "Wrong hour to call\n");
offset
= utcsec
- localsec
;
/* correct the kerneltime for this diffs */
/* subtract kernel offset, if present, old offset too */
diff
= oldoffset
+ tz
.tz_minuteswest
* 60 - offset
;
tv
.tv_usec
= 0; /* we are restarting here... */
if (tz
.tz_dsttime
!= 0 || tz
.tz_minuteswest
!= 0) {
tz
.tz_dsttime
= tz
.tz_minuteswest
= 0; /* zone info is garbage */
if (stz
!= NULL
|| stv
!= NULL
) {
if (settimeofday(stv
, stz
)) {
/****** End of critical section ******/
printf("Calculated zone offset diffs: %ld seconds\n", diff
);
if (offset
!= oldoffset
) {
/* Save offset for next calls from crontab */
if ((f
= fopen(storage
, "w")) == NULL
) {
fprintf(f
, "%ld\n", offset
);