Main Page | Class List | File List | Class Members | File Members

adjtimex.c File Reference

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <mat.h>
#include <math.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/timex.h>
#include <sys/types.h>
#include <syscall.h>
#include <time.h>
#include <unistd.h>
#include <utmp.h>
#include <sys/ioctl.h>
#include <linux/rtc.h>

Go to the source code of this file.

Classes

struct  cmos_adj

Defines

#define _GNU_SOURCE
#define LOG_PATH   "/var/log/clocks.log"
#define WTMP_PATH   "/var/log/wtmp"
#define ADJPATH   "/etc/adjtime"
#define RTC_JITTER   .000025
#define SECONDSPERDAY   86400
#define BUFLEN   128
#define CMOS_VALID   1
#define SYS_VALID   2
#define REF_VALID   4
#define HELP   131
#define CMOS_READ(addr)   ({outb(0x70,(addr)|0x80); inb(0x71);})
#define SHIFT   (1<<16)

Functions

 _syscall1 (int, adjtimex, struct timex *, txcp)
void compare (void)
void failntpdate ()
void reset_time_status (void)
static double compare_cmos_sys (void)
cmos_adjget_cmos_adjustment (void)
void log_times (void)
int valid_system_rate (double ftime_sys, double ftime_ref, double sigma_ref)
int valid_cmos_rate (double ftime_cmos, double ftime_ref, double sigma_ref)
void sethackent (void)
void endhackent (void)
hack * gethackent (void)
void puthackent (struct hack *ph)
time_t mkgmtime (struct tm *tp)
int compare_tm (struct tm *first, struct tm *second)
static void * xmalloc (int n)
static void * xrealloc (void *pv, int n)
void review (void)
void kalman_update (double *x, int xr, double *p, double *h, double *z, int zr, double *r)
void usage (void)
void probe_time (int *hz, int *tick_min, int *tick_mid, int *tick_max, long *maxfreq)
int main (int argc, char *argv[])
static void outb (short port, char val)
static unsigned char inb (short port)
void cmos_init ()
static int cmos_read_bcd (int addr)
static void cmos_read_time (struct tm *tm)
static void xusleep (long microseconds)

Variables

 prev
cmos_adj ca
timex txc
option longopt []
int adjusting = 0
int comparing = 0
int logging = 0
int reviewing = 0
int resetting = 0
int interval = 10
int count = 8
int marked
int universal = 0
int watch
int undisturbed_sys = 0
int undisturbed_cmos = 0
char * timeserver
static FILE * lfile


Define Documentation

#define _GNU_SOURCE
 

Definition at line 13 of file adjtimex.c.

#define ADJPATH   "/etc/adjtime"
 

Referenced by compare(), get_cmos_adjustment(), and valid_system_rate().

#define BUFLEN   128
 

Referenced by log_times(), valid_cmos_rate(), and valid_system_rate().

#define CMOS_READ addr   )     ({outb(0x70,(addr)|0x80); inb(0x71);})
 

Definition at line 559 of file adjtimex.c.

Referenced by cmos_read_bcd(), cmos_read_time(), and compare_cmos_sys().

#define CMOS_VALID   1
 

Definition at line 109 of file adjtimex.c.

Referenced by review().

#define HELP   131
 

Definition at line 122 of file adjtimex.c.

Referenced by main().

#define LOG_PATH   "/var/log/clocks.log"
 

#define REF_VALID   4
 

Definition at line 111 of file adjtimex.c.

Referenced by review().

#define RTC_JITTER   .000025
 

Referenced by review().

#define SECONDSPERDAY   86400
 

Referenced by compare(), and review().

#define SHIFT   (1<<16)
 

Referenced by compare(), and review().

#define SYS_VALID   2
 

Definition at line 110 of file adjtimex.c.

Referenced by review().

#define WTMP_PATH   "/var/log/wtmp"
 

Referenced by valid_system_rate().


Function Documentation

_syscall1 int  ,
adjtimex  ,
struct timex *  ,
txcp 
 

Definition at line 44 of file adjtimex.c.

00075                                             :
00076 
00077          * read RTC once any update in progress is done. The update
00078          * can take just over 2ms. We wait 10 to 20ms. There is no need to
00079          * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
00080          * If you need to know *exactly* when a second has started, enable
00081          * periodic update complete interrupts, (via ioctl) and then 
00082          * immediately read /dev/rtc which will block until you get the IRQ.
00083          * Once the read clears, read the RTC time (again via ioctl). Easy.
00084 
00085    However it doesn't say how to restore the interrupt setup.  Until I
00086    find out about that, I'll continue to use the poll-wait.  */
00087 static int using_dev_rtc = 0;
00088 
00089 struct hack {
00090   double ref;                   /* reference time for time hack */
00091   double sigma_ref;             /* expected error in above (or zero if
00092                                    no reference time available) */
00093   time_t log;                   /* reference time as time_t */
00094   double sys;                   /* system time */
00095   int tick;                     /* "tick" system parameter */
00096   int freq;                     /* "freq" system parameter */
00097   char sys_ok;                  /* nonzero if system clock undisturbed
00098                                    during previous period */
00099   double cmos;                  /* CMOS time */
00100   char cmos_ok;                 /* nonzero if cmos clock undisturbed
00101                                    during previous period */
00102   char valid;                   /* bit flags (see below) */
00103   double sys_rate, sys_sigma;
00104   double cmos_rate, cmos_sigma;
00105   double relative_rate, relative_sigma;
00106 } prev;

void cmos_init  ) 
 

Definition at line 522 of file adjtimex.c.

Referenced by compare(), and compare_cmos_sys().

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 }

static int cmos_read_bcd int  addr  )  [inline, static]
 

Definition at line 562 of file adjtimex.c.

References CMOS_READ.

Referenced by cmos_read_time(), and compare_cmos_sys().

00563 {
00564   int b;
00565 
00566   b = CMOS_READ (addr);
00567   return (b & 15) + (b >> 4) * 10;
00568 }

static void cmos_read_time struct tm *  tm  )  [static]
 

Definition at line 571 of file adjtimex.c.

References CMOS_READ, and cmos_read_bcd().

Referenced by compare().

00572 {
00573   if (using_dev_rtc > 0)
00574     ioctl (cmos_fd, RTC_RD_TIME, tm);
00575   else
00576     {
00577       long i;
00578 
00579       /* read RTC exactly on falling edge of update flag */
00580       /* Wait for rise.... (may take up to 1 second) */
00581 
00582       for (i = 0; i < 10000000; i++)
00583         if (CMOS_READ (10) & 0x80)
00584           break;
00585 
00586       /* Wait for fall.... (must try at least 2.228 ms) */
00587 
00588       for (i = 0; i < 1000000; i++)
00589         if (!(CMOS_READ (10) & 0x80))
00590           break;
00591 
00592       /* The "do" loop is "low-risk programming" */
00593       /* In theory it should never run more than once */
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 }

void compare void   ) 
 

Definition at line 623 of file adjtimex.c.

References ADJPATH, adjusting, cmos_init(), cmos_read_time(), count, interval, logging, marked, mkgmtime(), probe_time(), puthackent(), reset_time_status(), resetting, SECONDSPERDAY, SHIFT, universal, and xusleep().

Referenced by main().

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       /* Read adjustment parameters first */
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, &not_adjusted) < 0)
00651     {
00652       perror (ADJPATH);
00653       exit (2);
00654     }
00655   fclose (adj);
00656 #ifdef DEBUG
00657   /*
00658 cmos clock last adjusted at Tue Aug 26 11:43:57 1997 (= 872610237)
00659           current cmos time Tue Aug 26 21:27:05 1997 EDT (= 872645225)
00660 */
00661   {
00662     struct tm bdt;
00663     if (universal)
00664       {
00665         bdt = *gmtime(&last_time);
00666         (void)mkgmtime(&bdt);   /* set tzname */
00667       }
00668     else
00669       {
00670         bdt = *localtime(&last_time);
00671         (void)mktime(&bdt);     /* set tzname */
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       /* fetch system time immediately */
00688       gettimeofday (&now, NULL);
00689 
00690       tm.tm_mon--;              /* DOS uses 1 base */
00691       tm.tm_wday -= 3;          /* DOS uses 3 - 9 for week days */
00692       tm.tm_isdst = -1;         /* don't know whether it's daylight */
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       /* printf ("%s", asctime (&tm)); */
00701 
00702       system_sec = now.tv_sec + .000001*now.tv_usec;
00703 
00704       /* If we're adjusting time parameters, we want to make a log
00705          entry only for the first two comparisons (before we change
00706          the parameters).  Otherwise, we want to log the first and last
00707          comparisons in order to maximize the duration. */
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                                        --- current ---   -- suggested --
00754 cmos time     system-cmos  error_ppm   tick      freq    tick      freq
00755 1094939320  -14394.974188
00756 1094939330  -14394.971203      298.5  10001   1290819
00757 1094939340  -14394.968203      300.0  10001   1290819    9998   1289097
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         {                       /* print difference in rates */
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             {                   /* print suggested values */
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)                /* if it is not the last round */
00816         xusleep (interval*1000000L - 900000); /* reading RTC takes 1 sec */
00817     }
00818 }

static double compare_cmos_sys void   )  [static]
 

Definition at line 1219 of file adjtimex.c.

References cmos_init(), CMOS_READ, cmos_read_bcd(), mkgmtime(), and universal.

Referenced by log_times().

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)            /* also set tm_wday and tm_yday */
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                          /* I am superuser */
01264     {
01265       cmos_init ();
01266 
01267       /* read RTC exactly on falling edge of update flag */
01268       /* Wait for rise.... (may take up to 1 second) */
01269 
01270       for (i = 0; i < 10000000; i++)
01271         if (CMOS_READ (10) & 0x80)
01272           break;
01273 
01274       /* Wait for fall.... (must try at least 2.228 ms) */
01275 
01276       for (i = 0; i < 1000000; i++)
01277         if (!(CMOS_READ (10) & 0x80))
01278           break;
01279 
01280       /* The "do" loop is "low-risk programming" */
01281       /* In theory it should never run more than once */
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       /* fetch system time immediately */
01295       gettimeofday (&now, NULL);
01296 
01297       tm.tm_mon--;              /* DOS uses 1 base */
01298       tm.tm_wday -= 3;          /* DOS uses 3 - 9 for week days */
01299       tm.tm_isdst = -1;         /* don't know whether it's daylight */
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    * Mktime assumes we're giving it local time.  If the CMOS clock is in
01310    * GMT, we have to set up TZ so mktime knows it.  Tzset gets called
01311    * implicitly by the time code, but only the first time.  When
01312    * changing the environment variable, better call tzset explicitly.
01313    */
01314   if (universal)
01315     {
01316 #ifdef ZONESWITCH
01317       zone = (char *) getenv ("TZ");    /* save original time zone */
01318       (void) putenv ("TZ=");
01319       tzset ();
01320       cmos_time = mktime (&tm);
01321       /* now put back the original zone */
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         {                       /* wasn't one, so clear it */
01335           putenv ("TZ");
01336         }
01337       tzset ();
01338       printf ("%s", ctime (&cmos_time));
01339 #else /* !ZONESWITCH */
01340       cmos_time = mkgmtime(&tm);
01341 #endif
01342     }  
01343   else
01344     {
01345       cmos_time = mktime (&tm);
01346       /* printf ("%s", asctime (&tm)); */
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 }

int compare_tm struct tm *  first,
struct tm *  second
 

Definition at line 1498 of file adjtimex.c.

Referenced by mkgmtime().

01499 {
01500   if (first->tm_year < second->tm_year) return -1;
01501   if (first->tm_year > second->tm_year) return 1;
01502   if (first->tm_mon < second->tm_mon) return -1;
01503   if (first->tm_mon > second->tm_mon) return 1;
01504   if (first->tm_mday < second->tm_mday) return -1;
01505   if (first->tm_mday > second->tm_mday) return 1;
01506   if (first->tm_hour < second->tm_hour) return -1;
01507   if (first->tm_hour > second->tm_hour) return 1;
01508   if (first->tm_min < second->tm_min) return -1;
01509   if (first->tm_min > second->tm_min) return 1;
01510   if (first->tm_sec < second->tm_sec) return -1;
01511   if (first->tm_sec > second->tm_sec) return 1;
01512   return 0;
01513 }

void endhackent void   ) 
 

Definition at line 1381 of file adjtimex.c.

References lfile.

Referenced by review(), sethackent(), and valid_system_rate().

01382 {
01383   if (lfile) fclose(lfile);
01384   lfile = NULL;
01385 }

void failntpdate  ) 
 

Referenced by log_times().

struct cmos_adj * get_cmos_adjustment void   ) 
 

Definition at line 1193 of file adjtimex.c.

References ADJPATH, cmos_adj::ca_adj_time, cmos_adj::ca_factor, and cmos_adj::ca_remainder.

Referenced by review(), and valid_system_rate().

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 }

struct hack * gethackent void   ) 
 

Definition at line 1390 of file adjtimex.c.

References lfile, and sethackent().

Referenced by review(), and valid_system_rate().

01391 {
01392   char buf[256], sys_flag, cmos_flag, junk[26];
01393   static struct hack h;
01394 
01395   if (!lfile) sethackent();
01396   if (!lfile) return NULL;
01397   while(fgets(buf, sizeof(buf), lfile))
01398     {
01399       int tokens;
01400       if (buf[0] == '#')
01401         continue;
01402       tokens = sscanf(buf, "%25s %25s %lf %lf %lf %d %d %c %lf %c",
01403                       junk, junk, &h.ref, &h.sigma_ref, 
01404                       &h.sys, &h.tick, &h.freq, &sys_flag,
01405                       &h.cmos, &cmos_flag);
01406       if (tokens != 10)
01407         continue;
01408       h.sys_ok = (tolower(sys_flag) == 'y');      
01409       h.cmos_ok = (tolower(cmos_flag) == 'y');
01410       if (h.ref)
01411         h.log = (time_t)h.ref;
01412       else if (h.sys)
01413         h.log = (time_t)h.sys;
01414       else
01415         h.log = (time_t)h.cmos;
01416       h.valid = 0;
01417       return &h;
01418     }
01419   return NULL;
01420 }

static unsigned char inb short  port  )  [inline, static]
 

Definition at line 507 of file adjtimex.c.

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 }

void kalman_update double *  x,
int  xr,
double *  p,
double *  h,
double *  z,
int  zr,
double *  r
 

Definition at line 1801 of file adjtimex.c.

References mat_add(), mat_copy(), mat_mul(), mat_mul_nt(), mat_one(), mat_similarity(), mat_sub(), sym_factor(), and sym_rdiv().

Referenced by review().

01812 {
01813   static double k[4], num[4], denom[4], v[4], w[4];
01814   int pr=xr, pc=xr, 
01815     hr=zr, hc=xr, 
01816     rr=zr, rc=zr,
01817     kr=xr, kc=zr,
01818     nr=xr, nc=zr,
01819     dr=zr, dc=zr,
01820     vr=xr, vc=1,
01821     wr=zr, wc=1;
01822 
01823   /* find the Kalman gain k:
01824      k = p h' /(h p h' + r) */
01825   mat_mul_nt(p,pr,pc, h,hr,hc, num,nr,nc);
01826   mat_similarity(h,hr,hc, p,pr,pc, denom,dr,dc);
01827   mat_add(denom,dr,dc, r,rr,rc, denom,dr,dc);
01828   if (sym_factor(denom,dr,dc, denom,dr,dc))
01829     return;                     /* failure - singular */
01830   sym_rdiv(num,nr,nc, denom,dr,dc, k,kr,kc);
01831 
01832   /* update the state x:
01833      x <- x + k (z - h x) */
01834   mat_mul(h,hr,hc, x,xr,1, w,wr,wc);
01835   mat_sub(z,zr,1, w,wr,wc, w,wr,wc);
01836   mat_mul(k,kr,kc, w,wr,wc, v,vr,vc);
01837   mat_add(x,xr,1, v,vr,vc, x,xr,1);
01838 
01839   /* update the covariance p:
01840      p <- (I - k h) p */
01841   mat_one(v,xr,xr);
01842   mat_mul(k,kr,kc, h,hr,hc, w,xr,xr);
01843   mat_sub(v,xr,xr, w,xr,xr, w,xr,xr);
01844   mat_mul(w,xr,xr, p,xr,xr, v,xr,xr);
01845   mat_copy(v,xr,xr, p,xr,xr);
01846 }

void log_times void   ) 
 

Definition at line 843 of file adjtimex.c.

References BUFLEN, compare_cmos_sys(), failntpdate(), puthackent(), timeserver, txc, valid_cmos_rate(), valid_system_rate(), and watch.

Referenced by main().

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); /* set default values for most fields */
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); /* set time fields from user input */
00880         printf("      reference time is %s", asctime(&bdt));
00881         tref = ftime_ref = mktime(&bdt); /* construct a time_t
00882                                             corresponding to the user
00883                                             input */
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       /* read and save the significant lines, which should look like this:
00927 filter offset: -0.02800 -0.01354 -0.01026 -0.01385
00928 offset -0.013543
00929  1 Sep 11:51:23 ntpdate[598]: adjust time server 1.2.3.4 offset -0.013543 sec
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       /* ntpdate selects the offset from one of its samples (the one
00941          with the shortest round-trip delay?) */
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       /* The first saved line shows the offsets for each of ntpdate's
00954          samples.  Find their variance, which we will use to indicate
00955          the accuracy of the offset we're using.  This is probably
00956          conservative, since the offset we're using is probably not
00957          close to the mean. */
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       /* this is not even close to working yet */
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         int  connect(int  sockfd, struct sockaddr *serv_addr, int addrlen );
00983         int  send(int  s,  const void *msg, int len , unsigned int flags);
00984         int sendto(int s, const void *msg, int  len  unsigned  int
00985         flags, const struct sockaddr *to, int tolen);
00986         */
00987 #endif /* SEND */
00988       val = sendto(sockfd, (const void *)" ", 1, 0, &sa, len);
00989       if (val == -1) {perror("sendto"); exit(1);}
00990       sigma_ref = .010;
00991 #endif /* OWN_IMPLEMENTATION */
00992 
00993     }
00994   else                          /* no absolute time reference */
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                  -reference-time- --------system-time---------- --cmos-time----
01010 1997-06-14 20:22 888888888.888 -3 888888888.888 10000 6666666 n 888888888.888 y
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 }

int main int  argc,
char *  argv[]
 

Definition at line 273 of file adjtimex.c.

References adjusting, compare(), comparing, count, HELP, interval, log_path, log_times(), logging, longopt, probe_time(), reset_time_status(), resetting, review(), reviewing, timeserver, txc, universal, usage(), and watch.

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         if (geteuid() != 0)
00421           {
00422             fprintf(stderr, "sorry, only root can record clock comparisons\n");
00423             exit(1);
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"