00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #define _GNU_SOURCE
00014
00015 #include <ctype.h>
00016 #include <errno.h>
00017 #include <fcntl.h>
00018 #include <getopt.h>
00019 #include <mat.h>
00020 #include <math.h>
00021 #include <netdb.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <sys/socket.h>
00026 #include <sys/stat.h>
00027 #include <sys/time.h>
00028 #include <sys/timex.h>
00029 #include <sys/types.h>
00030 #include <syscall.h>
00031 #include <time.h>
00032 #include <unistd.h>
00033 #include <utmp.h>
00034 #include <fcntl.h>
00035 #include <sys/ioctl.h>
00036 #include <linux/rtc.h>
00037
00038 #ifdef __alpha__
00039 extern int adjtimex(struct timex *);
00040 #else
00041 #ifdef __ia64__
00042 extern int adjtimex(struct timex *);
00043 #else
00044 _syscall1(int, adjtimex, struct timex *, txcp)
00045 #endif
00046 #endif
00047 int F_print = 0;
00048
00049 #ifndef LOG_PATH
00050 #define LOG_PATH "/var/log/clocks.log"
00051 #endif
00052 #ifndef WTMP_PATH
00053 #define WTMP_PATH "/var/log/wtmp"
00054 #endif
00055
00056 static unsigned long epoch = 1900;
00057
00058
00059 #define ADJPATH "/etc/adjtime"
00060
00061
00062
00063
00064 #define RTC_JITTER .000025
00065 #define SECONDSPERDAY 86400
00066 #define BUFLEN 128
00067
00068 static int cmos_fd = -1;
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 static int using_dev_rtc = 0;
00088
00089 struct hack {
00090 double ref;
00091 double sigma_ref;
00092
00093 time_t log;
00094 double sys;
00095 int tick;
00096 int freq;
00097 char sys_ok;
00098
00099 double cmos;
00100 char cmos_ok;
00101
00102 char valid;
00103 double sys_rate, sys_sigma;
00104 double cmos_rate, cmos_sigma;
00105 double relative_rate, relative_sigma;
00106 } prev;
00107
00108
00109 #define CMOS_VALID 1
00110 #define SYS_VALID 2
00111 #define REF_VALID 4
00112
00113 struct cmos_adj
00114 {
00115 double ca_factor;
00116 long ca_adj_time;
00117 double ca_remainder;
00118 } ca;
00119
00120 struct timex txc;
00121
00122 #define HELP 131
00123
00124 struct option longopt[]=
00125 {
00126 {"adjust", 2, NULL, 'a'},
00127 {"compare", 2, NULL, 'c'},
00128 {"log", 2, NULL, 'l'},
00129 {"esterror", 1, NULL, 'e'},
00130 {"frequency", 1, NULL, 'f'},
00131 {"host", 1, NULL, 'h'},
00132 {"help", 0, NULL, HELP},
00133 {"interval", 1, NULL, 'i'},
00134 {"maxerror", 1, NULL, 'm'},
00135 {"offset", 1, NULL, 'o'},
00136 {"print", 0, NULL, 'p'},
00137 {"review", 2, NULL, 'r'},
00138 {"singleshot", 1, NULL, 's'},
00139 {"status", 1, NULL, 'S'},
00140 {"reset", 0, NULL, 'R'},
00141 {"timeconstant", 1, NULL, 'T'},
00142 {"tick", 1, NULL, 't'},
00143 {"utc", 0, NULL, 'u'},
00144 {"version", 0, NULL, 'v'},
00145 {"watch", 0, NULL, 'w'},
00146 {0,0,0,0}
00147 };
00148
00149 int adjusting = 0;
00150 int comparing = 0;
00151 int logging = 0;
00152 int reviewing = 0;
00153 int resetting = 0;
00154
00155 int interval = 10;
00156 int count = 8;
00157 int marked;
00158 int universal = 0;
00159 int watch;
00160 int undisturbed_sys = 0;
00161 int undisturbed_cmos = 0;
00162 char *log_path = LOG_PATH;
00163
00164 char *timeserver;
00165
00166 void compare(void);
00167 void failntpdate();
00168 void reset_time_status(void);
00169 static double compare_cmos_sys(void);
00170 struct cmos_adj *get_cmos_adjustment(void);
00171 void log_times(void);
00172 int valid_system_rate(double ftime_sys, double ftime_ref, double sigma_ref);
00173 int valid_cmos_rate(double ftime_cmos, double ftime_ref, double sigma_ref);
00174 void sethackent(void);
00175 void endhackent(void);
00176 struct hack *gethackent(void);
00177 void puthackent(struct hack *ph);
00178 time_t mkgmtime(struct tm *tp);
00179 int compare_tm(struct tm *first, struct tm *second);
00180 static void *xmalloc(int n);
00181 static void *xrealloc(void *pv, int n);
00182 void review(void);
00183 void kalman_update(double *x, int xr, double *p, double *h,
00184 double *z, int zr, double *r);
00185
00186 void
00187 usage(void)
00188 {
00189 char msg[]=
00190 "\n"
00191 "Usage: adjtimex [OPTION]... \n"
00192 "Mandatory or optional arguments to long options are mandatory or optional\n"
00193 "for short options too.\n"
00194 "\n"
00195 "Get/Set Kernel Time Parameters:\n"
00196 " -p, --print print values of kernel time variables\n"
00197 " -t, --tick val set the kernel tick interval in usec\n"
00198 " -f, --frequency newfreq set system clock frequency offset\n"
00199 " -s, --singleshot adj slew the system clock by adj usec\n"
00200 " -S, --status val set kernel clock status\n"
00201 " -R, --reset reset status after setting parameters\n"
00202 " (needed for early kernels)\n"
00203 " -o, --offset adj add a time offset of adj usec\n"
00204 " -m, --maxerror val set maximum error (usec)\n"
00205 " -e, --esterror val set estimated error (usec)\n"
00206 " -T, --timeconstant val set phase locked loop time constant\n"
00207 " -a, --adjust[=count] set system clock parameters per CMOS \n"
00208 " clock or (with --review) log file\n"
00209 "\n"
00210 "Estimate Systematic Drifts:\n"
00211 " -c, --compare[=count] compare system and CMOS clocks\n"
00212 " -i, --interval tim set clock comparison interval (sec)\n"
00213 " -l, --log[=file] log current times to file\n"
00214 " --host timeserver query the timeserver\n"
00215 " -w, --watch get current time from user\n"
00216 " -r, --review[=file] review clock log file, estimate drifts\n"
00217 " -u, --utc the CMOS clock is set to UTC\n"
00218 "\n"
00219 "Informative Output:\n"
00220 " --help print this help, then exit\n"
00221 " -v, --version print adjtimex program version, then exit\n"
00222 ;
00223
00224 fputs(msg, stdout);
00225 exit(0);
00226 }
00227
00228
00229
00230
00231 void probe_time(int *hz, int *tick_min, int *tick_mid, int *tick_max,
00232 long *maxfreq)
00233 {
00234 struct timex txc;
00235 int tick_orig, tick_lo, tick_try, tick_hi, i;
00236
00237 txc.modes = 0;
00238 adjtimex(&txc);
00239 *maxfreq = txc.tolerance;
00240 tick_orig = tick_hi = txc.tick;
00241 tick_lo = tick_hi*2/3;
00242 for (i = 0; i < 15; i++)
00243 {
00244
00245
00246 txc.tick = tick_try = (tick_lo + tick_hi)/2;
00247 txc.modes = ADJ_TICK;
00248 if (adjtimex(&txc) == -1) tick_lo = tick_try;
00249 else tick_hi = tick_try;
00250 }
00251 *tick_min = tick_hi;
00252 tick_lo = tick_orig;
00253 tick_hi = tick_lo*4/3;
00254 for (i = 0; i < 15; i++)
00255 {
00256
00257
00258 txc.tick = tick_try = (tick_lo + tick_hi)/2;
00259 txc.modes = ADJ_TICK;
00260 if (adjtimex(&txc) == -1) tick_hi = tick_try;
00261 else tick_lo = tick_try;
00262 }
00263 *tick_max = tick_lo;
00264 *tick_mid = (*tick_min + *tick_max)/2;
00265 *hz = (900000/ *tick_min + 1100000/ *tick_max)/2;
00266
00267 txc.tick = tick_orig;
00268 txc.modes = ADJ_TICK;
00269 adjtimex(&txc);
00270 }
00271
00272 int
00273 main(int argc, char *argv[])
00274 {
00275 int ret, saveerr, changes;
00276 extern char *optarg;
00277 int c;
00278
00279 txc.modes = 0;
00280
00281 while((c = getopt_long_only(argc, argv,
00282 "a::c::l::e:f:h:i:m:o:prPPsPS:RT:t:uvw",
00283 longopt, NULL)) != -1)
00284 {
00285 switch(c)
00286 {
00287 case 'a':
00288 adjusting = 1;
00289 if (optarg)
00290 count = atoi(optarg);
00291 break;
00292 case 'c':
00293 comparing = 1;
00294 if (optarg)
00295 count = atoi(optarg);
00296 break;
00297 case 'l':
00298 logging = 1;
00299 if (optarg)
00300 log_path = strdup(optarg);
00301 if (!log_path)
00302 {
00303 fprintf (stderr, "insufficient memory\n");
00304 exit(1);
00305 }
00306 break;
00307 case 'h':
00308 timeserver = strdup(optarg);
00309 if (!timeserver)
00310 {
00311 fprintf (stderr, "insufficient memory\n");
00312 exit(1);
00313 }
00314 logging = 1;
00315 break;
00316 case 'r':
00317 reviewing = 1;
00318 if (optarg)
00319 log_path = strdup(optarg);
00320 if (!log_path)
00321 {
00322 fprintf (stderr, "insufficient memory\n");
00323 exit(1);
00324 }
00325 break;
00326 case 'i':
00327 interval = atoi (optarg);
00328 if (interval <= 1 || interval > 1000)
00329 {
00330 fprintf (stderr, "repeat interval out of range\n");
00331 exit (1);
00332 }
00333 break;
00334 case 'p':
00335 F_print = 1;
00336 break;
00337 case 'o':
00338 txc.offset = atol(optarg);
00339 txc.modes |= ADJ_OFFSET;
00340 break;
00341 case 's':
00342 txc.offset = atol(optarg);
00343 txc.modes |= ADJ_OFFSET_SINGLESHOT;
00344 break;
00345 case 'S':
00346 txc.status = atol(optarg);
00347 txc.modes |= ADJ_STATUS;
00348 break;
00349 case 'R': resetting = 1; break;
00350 case 'f':
00351 txc.freq = atol(optarg);
00352 txc.modes |= ADJ_FREQUENCY;
00353 break;
00354 case 'm':
00355 txc.maxerror = atol(optarg);
00356 txc.modes |= ADJ_MAXERROR;
00357 break;
00358 case 'e':
00359 txc.esterror = atol(optarg);
00360 txc.modes |= ADJ_ESTERROR;
00361 break;
00362 case 'T':
00363 txc.constant = atol(optarg);
00364 txc.modes |= ADJ_TIMECONST;
00365 break;
00366 case 't':
00367 txc.tick = atol(optarg);
00368 txc.modes |= ADJ_TICK;
00369 break;
00370 case 'u':
00371 universal = 1;
00372 break;
00373 case 'v':
00374 {
00375 printf("adjtimex %s\n", VERSION);
00376 exit(0);
00377 }
00378 case 'w':
00379 watch = 1;
00380 logging = 1;
00381 break;
00382 case HELP:
00383 usage();
00384 break;
00385 case '?':
00386 default:
00387 fprintf(stderr, "For valid options, try 'adjtimex --help'\n");
00388 exit(1);
00389 }
00390 }
00391
00392 changes = txc.modes;
00393
00394 if (count <= 0 ) {
00395 fprintf(stderr, "loop count out of range\n");
00396 exit(1);
00397 }
00398
00399 if (reviewing)
00400 {
00401 review();
00402 exit(0);
00403 }
00404
00405 if (adjusting || comparing)
00406 {
00407 if (changes || F_print)
00408 {
00409 fprintf(stderr,
00410 "-adjust or -compare cannot be used with any other options that"
00411 " set values\n");
00412 exit(1);
00413 }
00414 compare();
00415 }
00416
00417 if (logging)
00418 {
00419
00420
00421
00422
00423
00424
00425
00426 log_times();
00427 exit(0);
00428 }
00429
00430 if ((txc.modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT &&
00431 txc.modes != ADJ_OFFSET_SINGLESHOT)
00432 {
00433 fprintf(stderr, "-singleshot cannot be used with "
00434 "any other option except -print\n");
00435 usage();
00436 }
00437
00438 errno = 0;
00439 ret = adjtimex(&txc);
00440 saveerr = errno;
00441 if (F_print) {
00442 printf(" mode: %d\n"
00443 " offset: %ld\n"
00444 " frequency: %ld\n"
00445 " maxerror: %ld\n"
00446 " esterror: %ld\n"
00447 " status: %d\n"
00448 "time_constant: %ld\n"
00449 " precision: %ld\n"
00450 " tolerance: %ld\n"
00451 " tick: %ld\n"
00452 " raw time: %ds %dus = %d.%06d\n",
00453 txc.modes,
00454 txc.offset,
00455 txc.freq,
00456 txc.maxerror,
00457 txc.esterror,
00458 txc.status,
00459 txc.constant,
00460 txc.precision,
00461 txc.tolerance,
00462 txc.tick,
00463 (int)txc.time.tv_sec,
00464 (int)txc.time.tv_usec,
00465 (int)txc.time.tv_sec,
00466 (int)txc.time.tv_usec);
00467 if (saveerr == 0 && ret != 0)
00468 printf(" return value = %d\n", ret);
00469 }
00470 if (ret != 0 && saveerr != 0) {
00471 if (ret != -1)
00472 fprintf(stderr, "%d ", ret);
00473 errno = saveerr;
00474 perror("adjtimex");
00475 {
00476 int hz, tick_min, tick_mid, tick_max;
00477 long maxfreq;
00478 probe_time(&hz, &tick_min, &tick_mid, &tick_max, &maxfreq);
00479
00480 printf("for this kernel:\n"
00481 " USER_HZ = %d (nominally %d ticks per second)\n"
00482 " %d <= tick <= %d\n"
00483 " %ld <= frequency <= %ld\n",
00484 hz, hz, tick_min, tick_max, -maxfreq, maxfreq);
00485 }
00486 exit(1);
00487 }
00488 if (changes && resetting)
00489 reset_time_status();
00490
00491 return 0;
00492 }
00493
00494 static inline void
00495 outb (short port, char val)
00496 {
00497 #ifdef USE_INLINE_ASM_IO
00498 __asm__ volatile ("out%B0 %0,%1"::"a" (val), "d" (port));
00499
00500 #else
00501 lseek (cmos_fd, port, 0);
00502 write (cmos_fd, &val, 1);
00503 #endif
00504 }
00505
00506 static inline unsigned char
00507 inb (short port)
00508 {
00509 unsigned char ret;
00510
00511 #ifdef USE_INLINE_ASM_IO
00512 __asm__ volatile ("in%B0 %1,%0":"=a" (ret):"d" (port));
00513
00514 #else
00515 lseek (cmos_fd, port, 0);
00516 read (cmos_fd, &ret, 1);
00517 #endif
00518 return ret;
00519 }
00520
00521 void
00522 cmos_init ()
00523 {
00524 if (using_dev_rtc < 0)
00525 {
00526 cmos_fd = open ("/dev/rtc", O_RDONLY);
00527 if (cmos_fd >= 0)
00528 {
00529 using_dev_rtc = 1;
00530 return;
00531 }
00532 using_dev_rtc = 0;
00533 }
00534 else if (using_dev_rtc > 0)
00535 return;
00536
00537 #ifdef USE_INLINE_ASM_IO
00538 if (ioperm (0x70, 2, 1))
00539 {
00540 fprintf (stderr, "clock: unable to get I/O port access\n");
00541 exit (1);
00542 }
00543 #else
00544 if (cmos_fd < 0)
00545 cmos_fd = open ("/dev/port", O_RDWR);
00546 if (cmos_fd < 0)
00547 {
00548 perror ("unable to open /dev/port read/write : ");
00549 exit (1);
00550 }
00551 if (lseek (cmos_fd, 0x70, 0) < 0 || lseek (cmos_fd, 0x71, 0) < 0)
00552 {
00553 perror ("unable to seek port 0x70 in /dev/port : ");
00554 exit (1);
00555 }
00556 #endif
00557 }
00558
00559 #define CMOS_READ(addr) ({outb(0x70,(addr)|0x80); inb(0x71);})
00560
00561 static inline int
00562 cmos_read_bcd (int addr)
00563 {
00564 int b;
00565
00566 b = CMOS_READ (addr);
00567 return (b & 15) + (b >> 4) * 10;
00568 }
00569
00570 static void
00571 cmos_read_time (struct tm *tm)
00572 {
00573 if (using_dev_rtc > 0)
00574 ioctl (cmos_fd, RTC_RD_TIME, tm);
00575 else
00576 {
00577 long i;
00578
00579
00580
00581
00582 for (i = 0; i < 10000000; i++)
00583 if (CMOS_READ (10) & 0x80)
00584 break;
00585
00586
00587
00588 for (i = 0; i < 1000000; i++)
00589 if (!(CMOS_READ (10) & 0x80))
00590 break;
00591
00592
00593
00594 do
00595 {
00596 tm->tm_sec = cmos_read_bcd (0);
00597 tm->tm_min = cmos_read_bcd (2);
00598 tm->tm_hour = cmos_read_bcd (4);
00599 tm->tm_wday = cmos_read_bcd (6);
00600 tm->tm_mday = cmos_read_bcd (7);
00601 tm->tm_mon = cmos_read_bcd (8);
00602 tm->tm_year = cmos_read_bcd (9);
00603 }
00604 while (tm->tm_sec != cmos_read_bcd (0));
00605 }
00606 }
00607
00608 static inline void
00609 xusleep(long microseconds)
00610 {
00611 struct timespec ts;
00612
00613 ts.tv_sec = microseconds/1000000;
00614 ts.tv_nsec = (microseconds - ts.tv_sec*1000000) * 1000;
00615
00616 while (nanosleep (&ts, &ts) < 0)
00617 continue;
00618 }
00619
00620
00621
00622 void
00623 compare()
00624 {
00625 struct timex txc;
00626 struct tm tm;
00627 time_t cmos_time;
00628 time_t last_time;
00629 double cmos_sec, system_sec, dif, dif_prev = 0.;
00630 FILE *adj;
00631 double factor;
00632 double cmos_adjustment;
00633 double not_adjusted;
00634 int loops = 0;
00635 extern char *optarg;
00636 struct timeval now;
00637 int wrote_to_log = 0;
00638 int hz, tick_min, tick_mid, tick_max;
00639 long maxfreq;
00640
00641 probe_time(&hz, &tick_min, &tick_mid, &tick_max, &maxfreq);
00642
00643
00644
00645 if ((adj = fopen (ADJPATH, "r")) == NULL)
00646 {
00647 perror (ADJPATH);
00648 exit (2);
00649 }
00650 if (fscanf (adj, "%lf %ld %lf", &factor, &last_time, ¬_adjusted) < 0)
00651 {
00652 perror (ADJPATH);
00653 exit (2);
00654 }
00655 fclose (adj);
00656 #ifdef DEBUG
00657
00658
00659
00660
00661 {
00662 struct tm bdt;
00663 if (universal)
00664 {
00665 bdt = *gmtime(&last_time);
00666 (void)mkgmtime(&bdt);
00667 }
00668 else
00669 {
00670 bdt = *localtime(&last_time);
00671 (void)mktime(&bdt);
00672 }
00673 printf ("cmos clock last adjusted %.24s %s "
00674 "(= %ld)\n",
00675 ctime(&last_time), tzname[tm.tm_isdst?1:0], (long) last_time);
00676 }
00677 #endif
00678
00679 cmos_init ();
00680
00681 while (count != 0)
00682 {
00683 if (count > 0) count--;
00684
00685 cmos_read_time (&tm);
00686
00687
00688 gettimeofday (&now, NULL);
00689
00690 tm.tm_mon--;
00691 tm.tm_wday -= 3;
00692 tm.tm_isdst = -1;
00693 if ((tm.tm_year += (epoch - 1900)) <= 69)
00694 tm.tm_year += 100;
00695
00696 if (universal)
00697 cmos_time = mkgmtime(&tm);
00698 else
00699 cmos_time = mktime (&tm);
00700
00701
00702 system_sec = now.tv_sec + .000001*now.tv_usec;
00703
00704
00705
00706
00707
00708 if (logging && (wrote_to_log ^ (adjusting?(loops==0):(count!=0))))
00709 {
00710 struct hack h;
00711
00712 h.ref = 0;
00713 h.sigma_ref = 0;
00714 h.log = (time_t)system_sec;
00715 h.sys = system_sec;
00716 txc.modes = 0;
00717 adjtimex(&txc);
00718 h.tick = txc.tick;
00719 h.freq = txc.freq;
00720 h.sys_ok = wrote_to_log;
00721 h.cmos = cmos_time;
00722 h.cmos_ok = wrote_to_log;
00723 puthackent(&h);
00724 wrote_to_log = 1;
00725 }
00726
00727 #ifdef DEBUG
00728 printf (" current cmos time %.24s %s (= %ld)\n",
00729 asctime(&tm), tzname[tm.tm_isdst?1:0], (long) cmos_time);
00730 #endif
00731 cmos_adjustment = ((double) (cmos_time - last_time))
00732 * factor / SECONDSPERDAY
00733 + not_adjusted;
00734 cmos_sec = cmos_time + cmos_adjustment;
00735 #ifdef DEBUG
00736 printf (
00737 " time since last adjustment %10.6f days (= %9d sec)\n",
00738 (int) (cmos_time - last_time) / (double)SECONDSPERDAY,
00739 (int) (cmos_time - last_time));
00740 printf (
00741 " factor %10.6f sec/day\n",
00742 factor);
00743 printf (
00744 " adjustment %10.6f + %7.6f = %7.6f sec\n",
00745 ((double) (cmos_time - last_time))*factor/SECONDSPERDAY,
00746 not_adjusted, cmos_adjustment);
00747 #endif
00748 dif = system_sec - cmos_sec;
00749
00750 txc.modes = 0;
00751 if (adjtimex (&txc) < 0) {perror ("adjtimex"); exit(1);}
00752
00753
00754
00755
00756
00757
00758
00759
00760 if (! marked++ )
00761 {
00762 if (interval)
00763 printf (
00764 " --- current --- -- suggested --\n"
00765 "cmos time system-cmos error_ppm tick freq tick freq\n");
00766 else
00767 printf (
00768 "cmos time system-cmos error_ppm tick freq\n");
00769 }
00770 printf ("%9ld %11.6f",
00771 (long) cmos_sec,
00772 dif);
00773 if (++loops > 1)
00774 {
00775 #define SHIFT (1<<16)
00776 double second_diff, error_ppm;
00777 second_diff = dif - dif_prev;
00778 error_ppm = second_diff/interval*1000000;
00779 printf ("%11.1f %6ld %9ld",
00780 error_ppm,
00781 txc.tick,
00782 txc.freq);
00783 if (loops > 2)
00784 {
00785 long tick_delta = 0, freq_delta = 0;
00786
00787 tick_delta = ceil((-error_ppm + txc.freq/SHIFT - hz)/hz);
00788 error_ppm += tick_delta*hz;
00789 freq_delta = -error_ppm*SHIFT;
00790 printf(" %6ld %9ld\n",
00791 txc.tick + tick_delta, txc.freq + freq_delta);
00792 if (loops > 4 && adjusting)
00793 {
00794 txc.modes = ADJ_FREQUENCY | ADJ_TICK;
00795 txc.tick += tick_delta;
00796 txc.freq += freq_delta;
00797 if (adjtimex (&txc) < 0)
00798 {
00799 perror ("adjtimex");
00800 exit(1);
00801 }
00802 if (resetting)
00803 reset_time_status();
00804 loops -= 3;
00805 }
00806 }
00807 else
00808 printf("\n");
00809 }
00810 else
00811 printf("\n");
00812 dif_prev = dif;
00813 if (interval == 0)
00814 break;
00815 if (count)
00816 xusleep (interval*1000000L - 900000);
00817 }
00818 }
00819
00820 void reset_time_status()
00821 {
00822
00823
00824
00825
00826
00827
00828
00829
00830 struct timeval tv1, tv2;
00831 long carry_sec, overhead_usec;
00832 if (gettimeofday(&tv1, NULL)) {perror("adjtimex"); exit(1);}
00833 if (gettimeofday(&tv2, NULL)) {perror("adjtimex"); exit(1);}
00834 overhead_usec = tv2.tv_usec - tv1.tv_usec +
00835 1000000*(tv2.tv_sec - tv1.tv_sec);
00836 tv2.tv_usec += overhead_usec;
00837 carry_sec = tv2.tv_usec/1000000;
00838 tv2.tv_sec += carry_sec;
00839 tv2.tv_usec -= 1000000*carry_sec;
00840 if (settimeofday(&tv2, NULL)) {perror("adjtimex"); exit(1);}
00841 }
00842
00843 void log_times()
00844 {
00845 #ifdef NET_TIME_CLIENT
00846 struct protoent proto;
00847 int sockfd, val, len, c;
00848 struct sockaddr sa={AF_INET, "127.0.0.1"};
00849 struct hostent he;
00850 #endif
00851 double sigma_ref, cmos_ahead;
00852 char ch, buf[64], *s;
00853 int n, ret;
00854 struct timeval tv_sys;
00855 struct timezone tz;
00856 struct tm bdt;
00857 time_t when, tref;
00858 double ftime_ref, ftime_sys, ftime_cmos;
00859
00860 if (watch)
00861 {
00862 while(1) {
00863 printf("Please press <enter> when you know the time of day: ");
00864 ch = getchar();
00865 gettimeofday(&tv_sys, &tz);
00866 when = tv_sys.tv_sec;
00867 bdt = *localtime(&when);
00868 strftime(buf, sizeof(buf), "%Z", &bdt);
00869 printf(" system time then was %.24s %s\n", asctime(&bdt), buf);
00870 ftime_sys = tv_sys.tv_sec + tv_sys.tv_usec*.000001;
00871 printf("What time was that according to your reference (%s)?\n"
00872 "(hh:mm:ss, or `r' to retry, or `q' to quit): ", buf);
00873 if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1);
00874 s = buf;
00875 while(isspace(*s)) s++;
00876 if (*s == 'q') exit(0);
00877 if (*s == 'r') continue;
00878
00879 strptime(buf, "%T", &bdt);
00880 printf(" reference time is %s", asctime(&bdt));
00881 tref = ftime_ref = mktime(&bdt);
00882
00883
00884 printf(" mktime returns time of %s", ctime(&tref));
00885
00886 printf("reference time - system time = %12.3f - %12.3f "
00887 "= %4.3f sec\n",
00888 ftime_ref, ftime_sys, ftime_ref - ftime_sys);
00889
00890 printf("How big could the error be in this, in seconds?\n"
00891 "(or `r' to retry, or `q' to quit) [.5] : ");
00892 if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1);
00893 s = buf;
00894 while(isspace(*s)) s++;
00895 if (*s == 'q') exit(0);
00896 if (*s == 'r') continue;
00897
00898 n = sscanf(buf, "%lf", &sigma_ref);
00899 if (n < 1)
00900 sigma_ref = .5;
00901 else if (sigma_ref < .02)
00902 {
00903 printf("You get credit for .02 sec.\n");
00904 sigma_ref = .02;
00905 }
00906 break;
00907 }
00908 }
00909 else if (timeserver)
00910 {
00911 FILE *ifile;
00912 char command[128];
00913 char buf[BUFLEN];
00914 char *str[5];
00915 int i, n=0;
00916 double d, mean=0, val, var=0, num=0;
00917
00918 #ifdef NTPDATE_STUB
00919 ifile = fopen("../ntpdate-sample", "r");
00920 #else
00921 sprintf(command, "ntpdate -d %.32s ", timeserver);
00922 ifile = popen(command, "r");
00923 #endif
00924 if (ifile == NULL) failntpdate("call to ntpdate failed");
00925
00926
00927
00928
00929
00930
00931 while(fgets(buf, BUFLEN, ifile))
00932 if (strstr(buf, "offset") && n < 4)
00933 str[n++] = strdup(buf);
00934 fclose(ifile);
00935 if (n != 3) failntpdate("cannot understand ntpdate output");
00936 gettimeofday(&tv_sys, &tz);
00937 ftime_sys = tv_sys.tv_sec;
00938
00939
00940
00941
00942 ftime_ref = ftime_sys + atof(strstr(str[2], "offset") + 6);
00943
00944 {
00945 time_t now = (time_t)ftime_ref;
00946 bdt = *gmtime(&now);
00947 printf(" reference time is %s", ctime(&now));
00948 printf("reference time - system time = %12.3f - %12.3f "
00949 "= %4.3f sec\n",
00950 ftime_ref, ftime_sys, ftime_ref - ftime_sys);
00951 }
00952
00953
00954
00955
00956
00957
00958 s = strstr(str[0], ":");
00959 if (s++ == NULL) failntpdate("cannot understand ntpdate output");
00960 for (i = 0; i < 4; i++)
00961 {
00962 val = strtod(s, &s);
00963 d = val - mean;
00964 num += 1.;
00965 var = (num-1)/num*(var + d*d/num);
00966 mean = ((num-1.)*mean + val)/num;
00967 }
00968 sigma_ref = sqrt(var);
00969
00970 #ifdef OWN_IMPLEMENTATION
00971
00972 proto = *getprotobyname("UDP");
00973 sockfd = socket(AF_INET, SOCK_DGRAM, proto.p_proto);
00974 he = *gethostbyname("localhost");
00975 len = he.h_length;
00976 memcpy(sa.sa_data, he.h_addr_list[0], len);
00977
00978 #ifdef SEND
00979 val = connect(sockfd, &sa, len);
00980 if (val == -1) {perror("connect"); exit(1);}
00981
00982
00983
00984
00985
00986
00987 #endif
00988 val = sendto(sockfd, (const void *)" ", 1, 0, &sa, len);
00989 if (val == -1) {perror("sendto"); exit(1);}
00990 sigma_ref = .010;
00991 #endif
00992
00993 }
00994 else
00995 {
00996 time_t now;
00997 gettimeofday(&tv_sys, &tz);
00998 now = (time_t)tv_sys.tv_sec;
00999 bdt = *gmtime(&now);
01000 ftime_sys = tv_sys.tv_sec + tv_sys.tv_usec*.000001;
01001 ftime_ref = 0;
01002 sigma_ref = 0;
01003 }
01004
01005 cmos_ahead = compare_cmos_sys();
01006 ftime_cmos = ftime_sys + cmos_ahead;
01007
01008
01009
01010
01011
01012
01013 {
01014 struct hack h;
01015 h.ref = ftime_ref;
01016 h.sigma_ref = sigma_ref;
01017 h.log = (time_t)ftime_ref;
01018 h.sys = ftime_sys;
01019 txc.modes = 0;
01020 ret = adjtimex(&txc);
01021 h.tick = txc.tick;
01022 h.freq = txc.freq;
01023 h.sys_ok = valid_system_rate(ftime_sys, ftime_ref, sigma_ref);
01024 h.cmos = ftime_cmos;
01025 h.cmos_ok = valid_cmos_rate(ftime_cmos, ftime_ref, sigma_ref);
01026 puthackent(&h);
01027 }
01028 }
01029
01030 void failntpdate(char *s)
01031 {
01032 fprintf(stderr, "%s\n", s);
01033 exit(1);
01034 }
01035
01036 int valid_system_rate(double ftime_sys, double ftime_ref, double sigma_ref)
01037 {
01038 int n;
01039 int default_answer;
01040 int ch;
01041 char buf[BUFLEN];
01042 struct hack *ph;
01043 struct cmos_adj *pca = get_cmos_adjustment();
01044
01045 sethackent();
01046 for (n = 0; (ph = gethackent()); n++)
01047 prev = *ph;
01048 endhackent();
01049 if (n == 0)
01050 {
01051 printf("No previous clock comparison in log file\n");
01052 return 0;
01053 }
01054 undisturbed_sys = undisturbed_cmos = 1;
01055
01056 printf("Last clock comparison was at %.24s\n", ctime(&prev.log));
01057
01058 if (txc.tick == prev.tick && txc.freq == prev.freq)
01059 printf("Kernel time variables are unchanged - good.\n");
01060 else
01061 {
01062 printf("Kernel time variables have changed - bad.\n");
01063 undisturbed_sys = 0;
01064 }
01065 if (txc.status & 64)
01066 printf("System clock is currently not disciplined - good.\n");
01067 else
01068 {
01069 printf("System clock is synchronized (by ntpd?) - bad.\n");
01070 undisturbed_sys = 0;
01071 }
01072
01073 {
01074 time_t lastboot, newtime;
01075 struct utmp *up;
01076
01077 lastboot = newtime = prev.sys - 1;
01078 utmpname(WTMP_PATH);
01079 setutent();
01080 printf("Checking wtmp file...\n");
01081 while((up = getutent()))
01082 {
01083 if (up->ut_type == BOOT_TIME)
01084 lastboot = up->ut_time;
01085 if (up->ut_type == NEW_TIME)
01086 newtime = up->ut_time;
01087 }
01088 endutent();
01089 if (lastboot < prev.sys)
01090 printf("System has not booted since %.24s - good.\n",
01091 ctime(&prev.log));
01092 else
01093 {
01094 printf("System was booted at %.24s - bad.\n", ctime(&lastboot));
01095 undisturbed_sys = 0;
01096 }
01097 if (newtime < prev.sys)
01098 printf("System time has not been changed since %.24s - good.\n",
01099 ctime(&prev.log));
01100 else
01101 {
01102 printf("System time was reset at %.24s - bad.\n", ctime(&newtime));
01103 undisturbed_sys = 0;
01104 }
01105 }
01106
01107 if (pca)
01108 {
01109 printf("Checking %s...\n", ADJPATH);
01110 if (pca->ca_adj_time < prev.log)
01111 printf(
01112 "/sbin/clock has not set system time and adjusted the cmos clock \n"
01113 "since %.24s - good.\n",
01114 ctime(&prev.log));
01115 else
01116 {
01117 printf("/sbin/clock set system time and adjusted the cmos clock \n"
01118 "at %.24s - bad.\n",
01119 ctime(&pca->ca_adj_time));
01120 undisturbed_sys = undisturbed_cmos = 0;
01121 }
01122 }
01123
01124 do
01125 {
01126 default_answer = undisturbed_sys?'y':'n';
01127 printf("\nAre you sure that, since %.24s,\n", ctime(&prev.log));
01128 printf(" the system clock has run continuously,\n");
01129 printf(" it has not been reset with `date' or `/sbin/clock`,\n");
01130 printf(" the kernel time variables have not been changed, and\n");
01131 printf(" the computer has not been suspended? (y/n) [%c] ",
01132 default_answer);
01133 fgets(buf, BUFLEN, stdin);
01134 ch = buf[0];
01135 if (ch == '\n') ch = default_answer;
01136 } while (ch != 'n' && ch != 'y');
01137
01138 if ((undisturbed_sys = (ch == 'y')))
01139 {
01140 double drift_sys_ppm, err_sys_ppm;
01141 int digits;
01142 drift_sys_ppm = ((ftime_sys - ftime_ref) - (prev.sys - prev.ref))*
01143 1.e6/(ftime_ref - prev.ref);
01144 err_sys_ppm = (prev.sigma_ref + sigma_ref)*1.e6/
01145 (ftime_ref - prev.ref);
01146 digits = -(int)floor(log(.5*sigma_ref)/log(10.));
01147 if (digits < 0) digits = 0;
01148
01149 printf("The estimated error in system time is %.*f +- %.*f ppm\n",
01150 digits, drift_sys_ppm, digits, err_sys_ppm);
01151 }
01152
01153 return undisturbed_sys;
01154 }
01155
01156 int valid_cmos_rate(double ftime_cmos, double ftime_ref, double sigma_ref)
01157 {
01158 int default_answer;
01159 int ch;
01160 char buf[BUFLEN];
01161
01162 default_answer = undisturbed_cmos?'y':'n';
01163 do
01164 {
01165 printf("\nAre you sure that, since %.24s,\n", ctime(&prev.log));
01166 printf(" the real time clock (cmos clock) has run continuously,\n");
01167 printf(" it has not been reset with `/sbin/clock',\n");
01168 printf(" no operating system other than Linux has been running, and\n");
01169 printf(" ntpd has not been running? (y/n) [%c] ", default_answer);
01170 fgets(buf, BUFLEN, stdin);
01171 ch = buf[0];
01172 if (ch == '\n') ch = default_answer;
01173 } while (ch != 'n' && ch != 'y');
01174 if ((undisturbed_cmos = (ch == 'y')))
01175 {
01176 double drift_cmos_ppm, err_cmos_ppm;
01177 int digits;
01178
01179 drift_cmos_ppm =
01180 ((ftime_cmos - ftime_ref) - (prev.cmos - prev.ref))*
01181 1.e6/(ftime_ref - prev.ref);
01182 err_cmos_ppm = (prev.sigma_ref + sigma_ref)*1.e6/
01183 (ftime_ref - prev.ref);
01184 digits = -(int)floor(log(.5*err_cmos_ppm)/log(10.));
01185 if (digits < 0) digits = 0;
01186 printf("The estimated error in the cmos clock is %.*f +- %.*f ppm\n",
01187 digits, drift_cmos_ppm, digits, err_cmos_ppm);
01188 }
01189
01190 return undisturbed_cmos;
01191 }
01192
01193 struct cmos_adj *get_cmos_adjustment()
01194 {
01195 FILE *adj;
01196 static struct cmos_adj ca;
01197 if ((adj = fopen (ADJPATH, "r")) == NULL)
01198 {
01199 perror (ADJPATH);
01200 exit (2);
01201 }
01202 if (fscanf (adj, "%lf %ld %lf",
01203 &ca.ca_factor,
01204 &ca.ca_adj_time,
01205 &ca.ca_remainder) < 0)
01206 {
01207 perror (ADJPATH);
01208 exit (2);
01209 }
01210 fclose (adj);
01211 #ifdef DEBUG
01212 printf ("CMOS clock was last adjusted %s", ctime(&ca.ca_adj_time));
01213 #endif
01214 return &ca;
01215 }
01216
01217
01218 static double
01219 compare_cmos_sys()
01220 {
01221 struct tm tm;
01222 time_t cmos_time;
01223 double system_sec;
01224 double dif;
01225 int i;
01226 extern char *optarg;
01227 struct timeval now;
01228
01229 if (geteuid() != 0)
01230 {
01231 struct tm bdt;
01232 char before[256], after[256];
01233 int fd = open("/proc/rtc", O_RDONLY);
01234 if (fd == -1)
01235 {
01236 fprintf(stderr, "kernel lacks enhanced real time clock support, "
01237 "so only root can read RTC\n");
01238 exit(1);
01239 }
01240 read(fd, before, sizeof(before));
01241 close(fd);
01242 do
01243 {
01244 fd = open("/proc/rtc", O_RDONLY);
01245 read(fd, after, sizeof(after));
01246 gettimeofday (&now, NULL);
01247 close(fd);
01248 } while (!strncmp(before, after, strlen(after)));
01249 strptime(after, "rtc_time : %H:%M:%S\nrtc_date : %Y-%m-%d", &bdt);
01250
01251 if (universal)
01252 cmos_time = mkgmtime(&bdt);
01253 else
01254 cmos_time = mktime(&bdt);
01255 #ifdef DEBUG
01256 printf("RTC says date & time are %.24s %s\n",
01257 asctime(&bdt), tzname[bdt.tm_isdst?1:0]);
01258 #endif
01259 system_sec = now.tv_sec + .000001 * now.tv_usec;
01260 dif = (double)cmos_time - system_sec;
01261 return dif;
01262 }
01263 else
01264 {
01265 cmos_init ();
01266
01267
01268
01269
01270 for (i = 0; i < 10000000; i++)
01271 if (CMOS_READ (10) & 0x80)
01272 break;
01273
01274
01275
01276 for (i = 0; i < 1000000; i++)
01277 if (!(CMOS_READ (10) & 0x80))
01278 break;
01279
01280
01281
01282 do
01283 {
01284 tm.tm_sec = cmos_read_bcd (0);
01285 tm.tm_min = cmos_read_bcd (2);
01286 tm.tm_hour = cmos_read_bcd (4);
01287 tm.tm_wday = cmos_read_bcd (6);
01288 tm.tm_mday = cmos_read_bcd (7);
01289 tm.tm_mon = cmos_read_bcd (8);
01290 tm.tm_year = cmos_read_bcd (9);
01291 }
01292 while (tm.tm_sec != cmos_read_bcd (0));
01293
01294
01295 gettimeofday (&now, NULL);
01296
01297 tm.tm_mon--;
01298 tm.tm_wday -= 3;
01299 tm.tm_isdst = -1;
01300 if ((tm.tm_year += (epoch - 1900)) <= 69)
01301 tm.tm_year += 100;
01302 #ifdef DEBUG
01303 printf (" mday=%d mon=%d wday=%d year=%d\n",
01304 tm.tm_mday, tm.tm_mon, tm.tm_wday, tm.tm_year);
01305 printf ("Cmos time %d:%02d:%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec);
01306 #endif
01307 }
01308
01309
01310
01311
01312
01313
01314 if (universal)
01315 {
01316 #ifdef ZONESWITCH
01317 zone = (char *) getenv ("TZ");
01318 (void) putenv ("TZ=");
01319 tzset ();
01320 cmos_time = mktime (&tm);
01321
01322 if (zone)
01323 {
01324 if ((strlen (zone) + 4) > sizeof (zonebuf))
01325 {
01326 fprintf (stderr, "Size of TZ variable is too long\n");
01327 exit (2);
01328 }
01329 strcpy (zonebuf, "TZ=");
01330 strcat (zonebuf, zone);
01331 putenv (zonebuf);
01332 }
01333 else
01334 {
01335 putenv ("TZ");
01336 }
01337 tzset ();
01338 printf ("%s", ctime (&cmos_time));
01339 #else
01340 cmos_time = mkgmtime(&tm);
01341 #endif
01342 }
01343 else
01344 {
01345 cmos_time = mktime (&tm);
01346
01347 }
01348
01349 system_sec = now.tv_sec + .000001 * now.tv_usec;
01350 #ifdef DEBUG
01351 printf ("Number of seconds since 1/1/1970 is %ld\n",
01352 (long) cmos_time);
01353 #endif
01354
01355 dif = (double)cmos_time - system_sec;
01356
01357 return dif;
01358 }
01359
01360
01361 static FILE *lfile;
01362
01363
01364 void sethackent(void)
01365 {
01366 endhackent();
01367 lfile = fopen(log_path, "r");
01368 if (!lfile && logging)
01369 {
01370 lfile = fopen(log_path, "a+");
01371 if (!lfile)
01372 {
01373 fprintf(stderr, "%s does not exist, and could not be created\n",
01374 log_path);
01375 exit(1);
01376 }
01377 fseek(lfile, 0L, 0);
01378 }
01379 }
01380
01381 void endhackent(void)
01382 {
01383 if (lfile) fclose(lfile);
01384 lfile = NULL;
01385 }
01386
01387
01388
01389
01390 struct hack *gethackent(void)
01391 {
01392 char buf[256], sys_flag, cmos_flag, junk[26];
01393 static struct hack h;
01394
01395 if (!lfile) sethackent