adjkerntz.c revision 882
1867Sache/* 2867Sache * Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia. 3867Sache * All rights reserved. 4867Sache * 5867Sache * Redistribution and use in source and binary forms, with or without 6867Sache * modification, are permitted provided that the following conditions 7867Sache * are met: 8867Sache * 1. Redistributions of source code must retain the above copyright 9867Sache * notice, this list of conditions and the following disclaimer. 10867Sache * 2. Redistributions in binary form must reproduce the above copyright 11867Sache * notice, this list of conditions and the following disclaimer in the 12867Sache * documentation and/or other materials provided with the distribution. 13867Sache * 14867Sache * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND 15867Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16867Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17867Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 18867Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19867Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20867Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21867Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22867Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23867Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24867Sache * SUCH DAMAGE. 25867Sache */ 26867Sache 27867Sache#ifndef lint 28867Sachechar copyright[] = 29867Sache"@(#)Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.\n\ 30867Sache All rights reserved.\n"; 31867Sache#endif /* not lint */ 32867Sache 33867Sache/* 34882Sache * Andrew A. Chernov <ache@astral.msk.su> Dec 20 1993 35867Sache * 36867Sache * Fix kernel time value if machine run wall CMOS clock 37867Sache * (and /etc/wall_cmos_clock file present) 38867Sache * using zoneinfo rules or direct TZ environment variable set. 39867Sache * Use Joerg Wunsch idea for seconds accurate offset calculation 40867Sache * with Garrett Wollman and Bruce Evans fixes. 41867Sache * 42867Sache */ 43867Sache#include <stdio.h> 44867Sache#include <stdlib.h> 45867Sache#include <unistd.h> 46867Sache#include <sys/stat.h> 47867Sache#include <sys/time.h> 48867Sache 49867Sache#include "pathnames.h" 50867Sache 51867Sachechar storage[] = _PATH_OFFSET; 52867Sache 53867Sacheint main(argc, argv) 54867Sache int argc; 55867Sache char **argv; 56867Sache{ 57867Sache struct tm local, utc; 58867Sache struct timeval tv, *stv; 59867Sache struct timezone tz, *stz; 60867Sache /* Avoid time_t here, can be unsigned long */ 61867Sache long offset, oldoffset, utcsec, localsec, diff; 62882Sache time_t final_sec; 63867Sache int ch, init = -1, verbose = 0; 64867Sache FILE *f; 65867Sache 66867Sache while ((ch = getopt(argc, argv, "aiv")) != EOF) 67867Sache switch((char)ch) { 68867Sache case 'i': /* initial call, save offset */ 69867Sache if (init != -1) 70867Sache goto usage; 71867Sache init = 1; 72867Sache break; 73867Sache case 'a': /* adjustment call, use saved offset */ 74867Sache if (init != -1) 75867Sache goto usage; 76867Sache init = 0; 77867Sache break; 78867Sache case 'v': /* verbose */ 79867Sache verbose = 1; 80867Sache break; 81867Sache default: 82867Sache usage: 83867Sache fprintf(stderr, "Usage:\n\ 84867Sache\tadjkerntz -i [-v]\t(initial call from /etc/rc)\n\ 85867Sache\tadjkerntz -a [-v]\t(adjustment call from crontab)\n"); 86867Sache return 2; 87867Sache } 88867Sache if (init == -1) 89867Sache goto usage; 90867Sache 91867Sache if (access(_PATH_CLOCK, F_OK)) 92867Sache return 0; 93867Sache 94867Sache /* Restore saved offset */ 95867Sache 96867Sache if (!init) { 97867Sache if ((f = fopen(storage, "r")) == NULL) { 98867Sache perror(storage); 99867Sache return 1; 100867Sache } 101867Sache if (fscanf(f, "%ld", &oldoffset) != 1) { 102867Sache fprintf(stderr, "Incorrect offset in %s\n", storage); 103867Sache return 1; 104867Sache } 105867Sache (void) fclose(f); 106867Sache } 107867Sache else 108867Sache oldoffset = 0; 109867Sache 110867Sache/****** Critical section, do all things as fast as possible ******/ 111867Sache 112867Sache /* get local CMOS clock and possible kernel offset */ 113867Sache if (gettimeofday(&tv, &tz)) { 114867Sache perror("gettimeofday"); 115867Sache return 1; 116867Sache } 117867Sache 118867Sache /* get the actual local timezone difference */ 119867Sache local = *localtime(&tv.tv_sec); 120867Sache utc = *gmtime(&tv.tv_sec); 121867Sache utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */ 122867Sache /* because it assumed local time */ 123867Sache 124867Sache /* calculate local CMOS diff from GMT */ 125867Sache 126867Sache utcsec = mktime(&utc); 127867Sache localsec = mktime(&local); 128867Sache if (utcsec == -1 || localsec == -1) { 129882Sache fprintf(stderr, "Wrong initial hour to call\n"); 130867Sache return 1; 131867Sache } 132867Sache offset = utcsec - localsec; 133867Sache 134867Sache /* correct the kerneltime for this diffs */ 135867Sache /* subtract kernel offset, if present, old offset too */ 136867Sache 137882Sache diff = offset - tz.tz_minuteswest * 60 - oldoffset; 138882Sache 139867Sache if (diff != 0) { 140882Sache 141882Sache /* Yet one step for final time */ 142882Sache 143882Sache final_sec = tv.tv_sec + diff; 144882Sache 145882Sache /* get the actual local timezone difference */ 146882Sache local = *localtime(&final_sec); 147882Sache utc = *gmtime(&final_sec); 148882Sache utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */ 149882Sache /* because it assumed local time */ 150882Sache 151882Sache utcsec = mktime(&utc); 152882Sache localsec = mktime(&local); 153882Sache if (utcsec == -1 || localsec == -1) { 154882Sache fprintf(stderr, "Wrong final hour to call\n"); 155882Sache return 1; 156882Sache } 157882Sache offset = utcsec - localsec; 158882Sache 159882Sache /* correct the kerneltime for this diffs */ 160882Sache /* subtract kernel offset, if present, old offset too */ 161882Sache 162882Sache diff = offset - tz.tz_minuteswest * 60 - oldoffset; 163882Sache 164882Sache if (diff != 0) { 165882Sache tv.tv_sec += diff; 166882Sache tv.tv_usec = 0; /* we are restarting here... */ 167882Sache stv = &tv; 168882Sache } 169882Sache else 170882Sache stv = NULL; 171867Sache } 172867Sache else 173867Sache stv = NULL; 174867Sache 175867Sache if (tz.tz_dsttime != 0 || tz.tz_minuteswest != 0) { 176867Sache tz.tz_dsttime = tz.tz_minuteswest = 0; /* zone info is garbage */ 177867Sache stz = &tz; 178867Sache } 179867Sache else 180867Sache stz = NULL; 181867Sache 182867Sache if (stz != NULL || stv != NULL) { 183867Sache if (settimeofday(stv, stz)) { 184867Sache perror("settimeofday"); 185867Sache return 1; 186867Sache } 187867Sache } 188867Sache 189867Sache/****** End of critical section ******/ 190867Sache 191867Sache if (verbose) 192867Sache printf("Calculated zone offset diffs: %ld seconds\n", diff); 193867Sache 194867Sache if (offset != oldoffset) { 195867Sache (void) umask(022); 196867Sache /* Save offset for next calls from crontab */ 197867Sache if ((f = fopen(storage, "w")) == NULL) { 198867Sache perror(storage); 199867Sache return 1; 200867Sache } 201867Sache fprintf(f, "%ld\n", offset); 202867Sache if (fclose(f)) { 203867Sache perror(storage); 204867Sache return 1; 205867Sache } 206867Sache } 207867Sache 208867Sache return 0; 209867Sache} 210867Sache 211