]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/timesync.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / aux / timesync.c
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <ip.h>
5 #include <mp.h>
6
7 /* nanosecond times */
8 #define SEC 1000000000LL
9 #define MIN (60LL*SEC)
10 #define HOUR (60LL*MIN)
11 #define DAY (24LL*HOUR)
12
13 enum {
14         Fs,
15         Rtc,
16         Ntp,
17         Utc,
18         Gps,
19
20         HZAvgSecs= 3*60,  /* target averaging period for frequency in seconds */
21         MinSampleSecs= 60,      /* minimum sampling time in seconds */
22 };
23
24
25 char *dir = "/tmp";     /* directory sample files live in */
26 char *logfile = "timesync";
27 char *timeserver;
28 char *Rootid;
29 int utcfil;
30 int gpsfil;
31 int debug;
32 int impotent;
33 int logging;
34 int type;
35 int gmtdelta;           /* rtc+gmtdelta = gmt */
36 uvlong avgerr;
37
38 /* ntp server info */
39 int stratum = 14;
40 vlong mydisp, rootdisp;
41 vlong mydelay, rootdelay;
42 vlong avgdelay;
43 vlong lastutc;
44 uchar rootid[4];
45 char *sysid;
46 int myprec;
47
48 /* list of time samples */
49 typedef struct Sample Sample;
50 struct Sample
51 {
52         Sample  *next;
53         uvlong  ticks;
54         vlong   ltime;
55         vlong   stime;
56 };
57
58 /* ntp packet */
59 typedef struct NTPpkt NTPpkt;
60 struct NTPpkt
61 {
62         uchar   mode;
63         uchar   stratum;
64         uchar   poll;
65         uchar   precision;
66         uchar   rootdelay[4];
67         uchar   rootdisp[4];
68         uchar   rootid[4];
69         uchar   refts[8];
70         uchar   origts[8];      /* departed client */
71         uchar   recvts[8];      /* arrived at server */
72         uchar   xmitts[8];      /* departed server */
73         uchar   keyid[4];
74         uchar   digest[16];
75 };
76
77 /* ntp server */
78 typedef struct NTPserver NTPserver;
79 struct NTPserver
80 {
81         NTPserver *next;
82         char    *name;
83         uchar   stratum;
84         uchar   precision;
85         vlong   rootdelay;
86         vlong   rootdisp;
87         vlong   rtt;
88         vlong   dt;
89 };
90
91 NTPserver *ntpservers;
92
93 enum
94 {
95         NTPSIZE=        48,     /* basic ntp packet */
96         NTPDIGESTSIZE=  20,     /* key and digest */
97 };
98
99 /* error bound of last sample */
100 ulong   ε;
101
102 static void     addntpserver(char *name);
103 static int      adjustperiod(vlong diff, vlong accuracy, int secs);
104 static void     background(void);
105 static int      caperror(vlong dhz, int tsecs, vlong taccuracy);
106 static long     fstime(void);
107 static int      gettime(vlong *nsec, uvlong *ticks, uvlong *hz); /* returns time, ticks, hz */
108 static int      getclockprecision(vlong);
109 static vlong    gpssample(void);
110 static void     hnputts(void *p, vlong nsec);
111 static void     hnputts(void *p, vlong nsec);
112 static void     inittime(void);
113 static vlong    nhgetts(void *p);
114 static vlong    nhgetts(void *p);
115 static void     ntpserver(char*);
116 static vlong    ntpsample(void);
117 static int      ntptimediff(NTPserver *ns);
118 static int      openfreqfile(void);
119 static vlong    readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz);
120 static long     rtctime(void);
121 static vlong    sample(long (*get)(void));
122 static void     setpriority(void);
123 static void     setrootid(char *d);
124 static void     settime(vlong now, uvlong hz, vlong delta, int n); /* set time, hz, delta, period */
125 static vlong    utcsample(void);
126 static uvlong   vabs(vlong);
127 static uvlong   whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz,
128                         vlong dt, vlong ticks, vlong period);
129 static void     writefreqfile(int fd, vlong hz, int secs, vlong diff);
130
131 // ((1970-1900)*365 + 17 /*leap days*/)*24*60*60
132 #define EPOCHDIFF 2208988800UL
133
134 static void
135 usage(void)
136 {
137         fprint(2, "usage: %s [-a accuracy][-d dir][-I rootid][-s net]"
138                 "[-S stratum][-DfGilLnrU] timesource ...\n", argv0);
139         exits("usage");
140 }
141
142 void
143 main(int argc, char **argv)
144 {
145         int i, t, fd, nservenet;
146         int secs;               /* sampling period */
147         int tsecs;              /* temporary sampling period */
148         uvlong hz, minhz, maxhz, period, nhz;
149         vlong diff, accuracy, taccuracy;
150         char *servenet[4];
151         Sample *s, *x, *first, **l;
152         Tm tl, tg;
153
154         type = Fs;              /* by default, sync with the file system */
155         debug = 0;
156         accuracy = 1000000LL;   /* default accuracy is 1 millisecond */
157         nservenet = 0;
158         tsecs = secs = MinSampleSecs;
159         timeserver = "";
160
161         ARGBEGIN{
162         case 'a':
163                 accuracy = strtoll(EARGF(usage()), 0, 0); /* specified in ns */
164                 if(accuracy <= 1)
165                         sysfatal("bad accuracy specified");
166                 break;
167         case 'd':
168                 dir = EARGF(usage());
169                 break;
170         case 'D':
171                 debug = 1;
172                 break;
173         case 'f':
174                 type = Fs;
175                 stratum = 2;
176                 break;
177         case 'G':
178                 type = Gps;
179                 stratum = 1;
180                 break;
181         case 'i':
182                 impotent = 1;
183                 break;
184         case 'I':
185                 Rootid = EARGF(usage());
186                 break;
187         case 'l':
188                 logging = 1;
189                 break;
190         case 'L':
191                 /*
192                  * Assume time source in local time rather than GMT.
193                  * Calculate difference so that rtctime can return GMT.
194                  * This is useful with the rtc on PC's that run Windows
195                  * since Windows keeps the local time in the rtc.
196                  */
197                 t = time(0);
198                 tl = *localtime(t);
199                 tg = *gmtime(t);
200
201                 /*
202                  * if the years are different, we're at most a day off,
203                  * so just rewrite
204                  */
205                 if(tl.year < tg.year){
206                         tg.year--;
207                         tg.yday = tl.yday + 1;
208                 }else if(tl.year > tg.year){
209                         tl.year--;
210                         tl.yday = tg.yday+1;
211                 }
212                 assert(tl.year == tg.year);
213
214                 tg.sec -= tl.sec;
215                 tg.min -= tl.min;
216                 tg.hour -= tl.hour;
217                 tg.yday -= tl.yday;
218                 gmtdelta = tg.sec+60*(tg.min+60*(tg.hour+tg.yday*24));
219
220                 assert(abs(gmtdelta) <= 24*60*60);
221                 break;
222         case 'n':
223                 type = Ntp;
224                 break;
225         case 'r':
226                 type = Rtc;
227                 stratum = 0;
228                 break;
229         case 'U':
230                 type = Utc;
231                 stratum = 1;
232                 break;
233         case 's':
234                 if(nservenet >= nelem(servenet))
235                         sysfatal("too many networks to serve on");
236                 servenet[nservenet++] = EARGF(usage());
237                 break;
238         case 'S':
239                 stratum = strtoll(EARGF(usage()), 0, 0);
240                 break;
241         default:
242                 usage();
243         }ARGEND;
244
245         fmtinstall('E', eipfmt);
246         fmtinstall('I', eipfmt);
247         fmtinstall('V', eipfmt);
248         sysid = getenv("sysname");
249
250         /* detach from the current namespace */
251         if(debug)
252                 rfork(RFNAMEG);
253
254         switch(type){
255         case Utc:
256                 if(argc > 0)
257                         timeserver = argv[0];
258                 else
259                         sysfatal("bad time source");
260                 break;
261         case Gps:
262                 if(argc > 0)
263                         timeserver = argv[0];
264                 else
265                         timeserver = "/mnt/gps/time";
266                 break;
267         case Fs:
268                 if(argc > 0)
269                         timeserver = argv[0];
270                 else
271                         timeserver = "/srv/boot";
272                 break;
273         case Ntp:
274                 if(argc > 0)
275                         for(i = 0; i < argc; i++)
276                                 addntpserver(argv[i]);
277                 else
278                         addntpserver("$ntp");
279                 break;
280         }
281
282         setpriority();
283
284         /* figure out our time interface and initial frequency */
285         inittime();
286         gettime(0, 0, &hz);
287         minhz = hz/10;
288         maxhz = hz*10;
289         myprec = getclockprecision(hz);
290
291         /* convert the accuracy from nanoseconds to ticks */
292         taccuracy = hz*accuracy/SEC;
293
294         /*
295          * bind in clocks
296          */
297         switch(type){
298         case Fs:
299                 fd = open(timeserver, ORDWR);
300                 if(fd < 0)
301                         sysfatal("opening %s: %r", timeserver);
302                 if(amount(fd, "/n/boot", MREPL, "") < 0)
303                         sysfatal("mounting %s: %r", timeserver);
304                 close(fd);
305                 break;
306         case Rtc:
307                 bind("#r", "/dev", MAFTER);
308                 if(access("/dev/rtc", AREAD) < 0)
309                         sysfatal("accessing /dev/rtc: %r");
310                 break;
311         case Utc:
312                 fd = open(timeserver, OREAD);
313                 if(fd < 0)
314                         sysfatal("opening %s: %r", timeserver);
315                 utcfil = fd;
316                 break;
317         case Gps:
318                 fd = open(timeserver, OREAD);
319                 if(fd < 0)
320                         sysfatal("opening %s: %r", timeserver);
321                 gpsfil = fd;
322                 break;
323         }
324
325         /*
326          * start a local ntp server(s)
327          */
328         for(i = 0; i < nservenet; i++)
329                 switch(rfork(RFPROC|RFFDG|RFMEM|RFNOWAIT)){
330                 case -1:
331                         sysfatal("forking: %r");
332                 case 0:
333                         ntpserver(servenet[i]);
334                         _exits(0);
335                 }
336
337         /* get the last known frequency from the file */
338         fd = openfreqfile();
339         hz = readfreqfile(fd, hz, minhz, maxhz);
340
341         /*
342          * this is the main loop.  it gets a sample, adjusts the
343          * clock and computes a sleep period until the next loop.
344          * we balance frequency drift against the length of the
345          * period to avoid blowing the accuracy limit.
346          */
347         first = nil;
348         l = &first;
349         avgerr = accuracy >> 1;
350         for(;; background(), sleep(tsecs*1000)){
351                 s = mallocz(sizeof *s, 1);
352                 diff = 0;
353
354                 /* get times for this sample */
355                 ε = ~0;
356                 switch(type){
357                 case Fs:
358                         s->stime = sample(fstime);
359                         break;
360                 case Rtc:
361                         s->stime = sample(rtctime);
362                         break;
363                 case Utc:
364                         s->stime = utcsample();
365                         if(s->stime == 0LL){
366                                 if(logging)
367                                         syslog(0, logfile, "no sample");
368                                 free(s);
369                                 if (secs > 60 * 15)
370                                         tsecs = 60*15;
371                                 continue;
372                         }
373                         break;
374                 case Ntp:
375                         diff = ntpsample();
376                         if(diff == 0LL){
377                                 if(logging)
378                                         syslog(0, logfile, "no sample");
379                                 free(s);
380                                 if(secs > 60*15)
381                                         tsecs = 60*15;
382                                 continue;
383                         }
384                         break;
385                 case Gps:
386                         diff = gpssample();
387                         if(diff == 0LL){
388                                 if(logging)
389                                         syslog(0, logfile, "no sample");
390                                 free(s);
391                                 if(secs > 60*15)
392                                         tsecs = 60*15;
393                                 continue;
394                         }
395                 }
396
397                 /* use fastest method to read local clock and ticks */
398                 gettime(&s->ltime, &s->ticks, 0);
399                 if(type == Ntp || type == Gps)
400                         s->stime = s->ltime + diff;
401
402                 /* if the sample was bad, ignore it */
403                 if(s->stime < 0){
404                         free(s);
405                         continue;
406                 }
407
408                 /* reset local time */
409                 diff = s->stime - s->ltime;
410                 if(diff > 10*SEC || diff < -10*SEC){
411                         /* we're way off, just set the time */
412                         secs = MinSampleSecs;
413                         settime(s->stime, 0, 0, 0);
414                 } else {
415                         /* keep a running average of the error. */
416                         avgerr = (avgerr>>1) + (vabs(diff)>>1);
417
418                         /*
419                          * the time to next sample depends on how good or
420                          * bad we're doing.
421                          */
422                         tsecs = secs = adjustperiod(diff, accuracy, secs);
423
424                         /*
425                          * work off the fixed difference.  This is done
426                          * by adding a ramp to the clock.  Each 100th of a
427                          * second (or so) the kernel will add diff/(4*secs*100)
428                          * to the clock.  we only do 1/4 of the difference per
429                          * period to dampen any measurement noise.
430                          *
431                          * any difference greater than ε we work off during the
432                          * sampling period.
433                          */
434                         if(abs(diff) > ε)
435                                 if(diff > 0)
436                                         settime(-1, 0, diff-((3*ε)/4), secs);
437                                 else
438                                         settime(-1, 0, diff+((3*ε)/4), secs);
439                         else
440                                 settime(-1, 0, diff, 4*secs);
441
442                 }
443                 if(debug)
444                         fprint(2, "δ %lld avgδ %lld f %lld\n", diff, avgerr, hz);
445
446                 /* dump old samples (keep at least one) */
447                 while(first != nil){
448                         if(first->next == nil)
449                                 break;
450                         if(s->stime - first->next->stime < DAY)
451                                 break;
452                         x = first;
453                         first = first->next;
454                         free(x);
455                 }
456
457                 /*
458                  * The sampling error is limited by the total error.  If
459                  * we make sure the sampling period is at least 16 million
460                  * times the average error, we should calculate a frequency
461                  * with on average a 1e-7 error.
462                  *
463                  * So that big hz changes don't blow our accuracy requirement,
464                  * we shorten the period to make sure that δhz*secs will be
465                  * greater than the accuracy limit.
466                  */
467                 period = avgerr << 24;
468                 for(x = first; x != nil; x = x->next)
469                         if(s->stime - x->stime < period ||
470                            x->next == nil || s->stime - x->next->stime < period)
471                                 break;
472                 if(x != nil){
473                         nhz = whatisthefrequencykenneth(
474                                 hz, minhz, maxhz,
475                                 s->stime - x->stime,
476                                 s->ticks - x->ticks,
477                                 period);
478                         tsecs = caperror(vabs(nhz-hz), tsecs, taccuracy);
479                         hz = nhz;
480                         writefreqfile(fd, hz, (s->stime - x->stime)/SEC, diff);
481                 }
482
483                 /* add current sample to list. */
484                 *l = s;
485                 l = &s->next;
486
487                 if(logging)
488                         syslog(0, logfile, "δ %lld avgδ %lld hz %lld",
489                                 diff, avgerr, hz);
490         }
491 }
492
493 /*
494  * adjust the sampling period with some histeresis
495  */
496 static int
497 adjustperiod(vlong diff, vlong accuracy, int secs)
498 {
499         uvlong absdiff;
500
501         absdiff = vabs(diff);
502
503         if(absdiff < (accuracy>>1))
504                 secs += 60;
505         else if(absdiff > accuracy)
506                 secs >>= 1;
507         else
508                 secs -= 60;
509         if(secs < MinSampleSecs)
510                 secs = MinSampleSecs;
511         return secs;
512 }
513
514 /*
515  * adjust the frequency
516  */
517 static uvlong
518 whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz, vlong dt,
519         vlong ticks, vlong period)
520 {
521         uvlong ohz = hz;
522         static mpint *mpdt, *mpticks, *mphz, *mpbillion;
523
524         /* sanity check */
525         if(dt <= 0 || ticks <= 0)
526                 return hz;
527
528         if(mphz == nil){
529                 mphz = mpnew(0);
530                 mpbillion = uvtomp(SEC, nil);
531         }
532
533         /* hz = (ticks*SEC)/dt */
534         mpdt = vtomp(dt, mpdt);
535         mpticks = vtomp(ticks, mpticks);
536         mpmul(mpticks, mpbillion, mpticks);
537         mpdiv(mpticks, mpdt, mphz, nil);
538         hz = mptoui(mphz);
539
540         /* sanity */
541         if(hz < minhz || hz > maxhz)
542                 return ohz;
543
544         /* damp the change if we're shorter than the target period */
545         if(period > dt)
546                 hz = (12ULL*ohz + 4ULL*hz)/16ULL;
547
548         settime(-1, hz, 0, 0);
549         return hz;
550 }
551
552 /*
553  * We may be changing the frequency to match a bad measurement
554  * or to match a condition no longer in effect.  To make sure
555  * that this doesn't blow our error budget over the next measurement
556  * period, shorten the period to make sure that δhz*secs will be
557  * less than the accuracy limit.  Here taccuracy is accuracy converted
558  * from nanoseconds to ticks.
559  */
560 static int
561 caperror(vlong dhz, int tsecs, vlong taccuracy)
562 {
563         if(dhz*tsecs <= taccuracy)
564                 return tsecs;
565
566         if(debug)
567                 fprint(2, "δhz %lld tsecs %d tacc %lld\n", dhz, tsecs, taccuracy);
568
569         tsecs = taccuracy/dhz;
570         if(tsecs < MinSampleSecs)
571                 tsecs = MinSampleSecs;
572         return tsecs;
573 }
574
575 /*
576  *  kernel interface
577  */
578 enum
579 {
580         Ibintime,
581         Insec,
582         Itiming,
583 };
584 int ifc;
585 int bintimefd = -1;
586 int timingfd = -1;
587 int nsecfd = -1;
588 int fastclockfd = -1;
589
590 static void
591 inittime(void)
592 {
593         int mode;
594
595         if(impotent)
596                 mode = OREAD;
597         else
598                 mode = ORDWR;
599
600         /* bind in clocks */
601         if(access("/dev/time", 0) < 0)
602                 bind("#c", "/dev", MAFTER);
603         if(access("/dev/rtc", 0) < 0)
604                 bind("#r", "/dev", MAFTER);
605
606         /* figure out what interface we have */
607         ifc = Ibintime;
608         bintimefd = open("/dev/bintime", mode);
609         if(bintimefd >= 0)
610                 return;
611         ifc = Insec;
612         nsecfd = open("/dev/nsec", mode);
613         if(nsecfd < 0)
614                 sysfatal("opening /dev/nsec");
615         fastclockfd = open("/dev/fastclock", mode);
616         if(fastclockfd < 0)
617                 sysfatal("opening /dev/fastclock");
618         timingfd = open("/dev/timing", OREAD);
619         if(timingfd < 0)
620                 return;
621         ifc = Itiming;
622 }
623
624 /*
625  *  convert binary numbers from/to kernel
626  */
627 static uvlong uvorder = 0x0001020304050607ULL;
628
629 static uchar*
630 be2vlong(vlong *to, uchar *f)
631 {
632         uchar *t, *o;
633         int i;
634
635         t = (uchar*)to;
636         o = (uchar*)&uvorder;
637         for(i = 0; i < sizeof(vlong); i++)
638                 t[o[i]] = f[i];
639         return f+sizeof(vlong);
640 }
641
642 static uchar*
643 vlong2be(uchar *t, vlong from)
644 {
645         uchar *f, *o;
646         int i;
647
648         f = (uchar*)&from;
649         o = (uchar*)&uvorder;
650         for(i = 0; i < sizeof(vlong); i++)
651                 t[i] = f[o[i]];
652         return t+sizeof(vlong);
653 }
654
655 static long order = 0x00010203;
656
657 static uchar*
658 be2long(long *to, uchar *f)
659 {
660         uchar *t, *o;
661         int i;
662
663         t = (uchar*)to;
664         o = (uchar*)&order;
665         for(i = 0; i < sizeof(long); i++)
666                 t[o[i]] = f[i];
667         return f+sizeof(long);
668 }
669
670 static uchar*
671 long2be(uchar *t, long from)
672 {
673         uchar *f, *o;
674         int i;
675
676         f = (uchar*)&from;
677         o = (uchar*)&order;
678         for(i = 0; i < sizeof(long); i++)
679                 t[i] = f[o[i]];
680         return t+sizeof(long);
681 }
682
683 /*
684  * read ticks and local time in nanoseconds
685  */
686 static int
687 gettime(vlong *nsec, uvlong *ticks, uvlong *hz)
688 {
689         int i, n;
690         uchar ub[3*8], *p;
691         char b[2*24+1];
692
693         switch(ifc){
694         case Ibintime:
695                 n = sizeof(vlong);
696                 if(hz != nil)
697                         n = 3*sizeof(vlong);
698                 if(ticks != nil)
699                         n = 2*sizeof(vlong);
700                 i = read(bintimefd, ub, n);
701                 if(i != n)
702                         break;
703                 p = ub;
704                 if(nsec != nil)
705                         be2vlong(nsec, ub);
706                 p += sizeof(vlong);
707                 if(ticks != nil)
708                         be2vlong((vlong*)ticks, p);
709                 p += sizeof(vlong);
710                 if(hz != nil)
711                         be2vlong((vlong*)hz, p);
712                 return 0;
713         case Itiming:
714                 n = sizeof(vlong);
715                 if(ticks != nil)
716                         n = 2*sizeof(vlong);
717                 i = read(timingfd, ub, n);
718                 if(i != n)
719                         break;
720                 p = ub;
721                 if(nsec != nil)
722                         be2vlong(nsec, ub);
723                 p += sizeof(vlong);
724                 if(ticks != nil)
725                         be2vlong((vlong*)ticks, p);
726                 if(hz != nil){
727                         seek(fastclockfd, 0, 0);
728                         n = read(fastclockfd, b, sizeof(b)-1);
729                         if(n <= 0)
730                                 break;
731                         b[n] = 0;
732                         *hz = strtoll(b+24, 0, 0);
733                 }
734                 return 0;
735         case Insec:
736                 if(nsec != nil){
737                         seek(nsecfd, 0, 0);
738                         n = read(nsecfd, b, sizeof(b)-1);
739                         if(n <= 0)
740                                 break;
741                         b[n] = 0;
742                         *nsec = strtoll(b, 0, 0);
743                 }
744                 if(ticks != nil){
745                         seek(fastclockfd, 0, 0);
746                         n = read(fastclockfd, b, sizeof(b)-1);
747                         if(n <= 0)
748                                 break;
749                         b[n] = 0;
750                         *ticks = strtoll(b, 0, 0);
751                 }
752                 if(hz != nil){
753                         seek(fastclockfd, 0, 0);
754                         n = read(fastclockfd, b, sizeof(b)-1);
755                         if(n <= 24)
756                                 break;
757                         b[n] = 0;
758                         *hz = strtoll(b+24, 0, 0);
759                 }
760                 return 0;
761         }
762         return -1;
763 }
764
765 static void
766 settime(vlong now, uvlong hz, vlong delta, int n)
767 {
768         uchar b[1+sizeof(vlong)+sizeof(long)], *p;
769
770         if(debug)
771                 fprint(2, "settime(now=%lld, hz=%llud, delta=%lld, period=%d)\n",
772                         now, hz, delta, n);
773         if(impotent)
774                 return;
775         switch(ifc){
776         case Ibintime:
777                 if(now >= 0){
778                         p = b;
779                         *p++ = 'n';
780                         p = vlong2be(p, now);
781                         if(write(bintimefd, b, p-b) < 0)
782                                 sysfatal("writing /dev/bintime: %r");
783                 }
784                 if(delta != 0){
785                         p = b;
786                         *p++ = 'd';
787                         p = vlong2be(p, delta);
788                         p = long2be(p, n);
789                         if(write(bintimefd, b, p-b) < 0)
790                                 sysfatal("writing /dev/bintime: %r");
791                 }
792                 if(hz != 0){
793                         p = b;
794                         *p++ = 'f';
795                         p = vlong2be(p, hz);
796                         if(write(bintimefd, b, p-b) < 0)
797                                 sysfatal("writing /dev/bintime: %r");
798                 }
799                 break;
800         case Itiming:
801         case Insec:
802                 seek(nsecfd, 0, 0);
803                 if(now >= 0 || delta != 0){
804                         if(fprint(nsecfd, "%lld %lld %d", now, delta, n) < 0)
805                                 sysfatal("writing /dev/nsec: %r");
806                 }
807                 if(hz > 0){
808                         seek(fastclockfd, 0, 0);
809                         if(fprint(fastclockfd, "%lld", hz) < 0)
810                                 sysfatal("writing /dev/fastclock: %r");
811                 }
812         }
813 }
814
815 /*
816  *  set priority high and wire process to a processor
817  */
818 static void
819 setpriority(void)
820 {
821         int fd;
822         char buf[32];
823
824         sprint(buf, "/proc/%d/ctl", getpid());
825         fd = open(buf, ORDWR);
826         if(fd < 0){
827                 fprint(2, "can't set priority\n");
828                 return;
829         }
830         if(fprint(fd, "pri 100") < 0)
831                 fprint(2, "can't set priority\n");
832         if(fprint(fd, "wired 2") < 0)
833                 fprint(2, "can't wire process\n");
834         close(fd);
835 }
836
837 /* convert to ntp timestamps */
838 static void
839 hnputts(void *p, vlong nsec)
840 {
841         uchar *a;
842         ulong tsh, tsl;
843
844         a = p;
845
846         /* zero is a special case */
847         if(nsec == 0)
848                 return;
849
850         tsh = nsec/SEC;
851         nsec -= tsh*SEC;
852         tsl = (nsec<<32)/SEC;
853         hnputl(a, tsh+EPOCHDIFF);
854         hnputl(a+4, tsl);
855 }
856
857 /* convert from ntp timestamps */
858 static vlong
859 nhgetts(void *p)
860 {
861         uchar *a;
862         ulong tsh, tsl;
863         vlong nsec;
864
865         a = p;
866         tsh = nhgetl(a);
867         tsl = nhgetl(a+4);
868         nsec = tsl*SEC;
869         nsec >>= 32;
870         nsec += (tsh - EPOCHDIFF)*SEC;
871         return nsec;
872 }
873
874 /* convert to ntp 32 bit fixed point */
875 static void
876 hnputfp(void *p, vlong nsec)
877 {
878         uchar *a;
879         ulong fp;
880
881         a = p;
882
883         fp = nsec/(SEC/((vlong)(1<<16)));
884         hnputl(a, fp);
885 }
886
887 /* convert from ntp fixed point to nanosecs */
888 static vlong
889 nhgetfp(void *p)
890 {
891         uchar *a;
892         ulong fp;
893         vlong nsec;
894
895         a = p;
896         fp = nhgetl(a);
897         nsec = ((vlong)fp)*(SEC/((vlong)(1<<16)));
898         return nsec;
899 }
900
901 /* get network address of the server */
902 static void
903 setrootid(char *d)
904 {
905         char buf[128];
906         int fd, n;
907         char *p;
908
909         snprint(buf, sizeof buf, "%s/remote", d);
910         fd = open(buf, OREAD);
911         if(fd < 0)
912                 return;
913         n = read(fd, buf, sizeof buf);
914         close(fd);
915         if(n <= 0)
916                 return;
917         p = strchr(buf, '!');
918         if(p != nil)
919                 *p = 0;
920         v4parseip(rootid, buf);
921 }
922
923 static void
924 ding(void*, char *s)
925 {
926         if(strstr(s, "alarm") != nil)
927                 noted(NCONT);
928         noted(NDFLT);
929 }
930
931 static void
932 addntpserver(char *name)
933 {
934         NTPserver *ns, **l;
935
936         ns = mallocz(sizeof(NTPserver), 1);
937         if(ns == nil)
938                 sysfatal("addntpserver: %r");
939         timeserver = strdup(name);
940         ns->name = name;
941         for(l = &ntpservers; *l != nil; l = &(*l)->next)
942                 ;
943         *l = ns;
944 }
945
946 /*
947  *  sntp client, we keep calling if the delay seems
948  *  unusually high, i.e., 30% longer than avg.
949  */
950 static int
951 ntptimediff(NTPserver *ns)
952 {
953         int fd, tries, n;
954         NTPpkt ntpin, ntpout;
955         vlong dt, recvts, origts, xmitts, destts, x;
956         char dir[64];
957         static int whined;
958
959         notify(ding);
960         alarm(30*1000); /* don't wait forever if ns->name is unreachable */
961         fd = dial(netmkaddr(ns->name, "udp", "ntp"), 0, dir, 0);
962         if(fd < 0){
963                 if (!whined++)
964                         syslog(0, logfile, "can't reach %s: %r", ns->name);
965                 return -1;
966         }
967         setrootid(dir);
968
969         memset(&ntpout, 0, sizeof(ntpout));
970         ntpout.mode = 3 | (3 << 3);
971
972         for(tries = 0; tries < 3; tries++){
973                 alarm(2*1000);
974
975                 gettime(&x, 0, 0);
976                 hnputts(ntpout.xmitts, x);
977                 if(write(fd, &ntpout, NTPSIZE) < 0){
978                         alarm(0);
979                         continue;
980                 }
981
982                 n = read(fd, &ntpin, sizeof ntpin);
983                 alarm(0);
984                 gettime(&destts, 0, 0);
985                 if(n >= NTPSIZE){
986                         close(fd);
987
988                         /* we got one, use it */
989                         recvts = nhgetts(ntpin.recvts);
990                         origts = nhgetts(ntpin.origts);
991                         xmitts = nhgetts(ntpin.xmitts);
992                         dt = ((recvts - origts) + (xmitts - destts))/2;
993
994                         /* save results */
995                         ns->rtt = ((destts - origts) - (xmitts - recvts))/2;
996                         ns->dt = dt;
997                         ns->stratum = ntpin.stratum;
998                         ns->precision = ntpin.precision;
999                         ns->rootdelay = nhgetfp(ntpin.rootdelay);
1000                         ns->rootdisp = nhgetfp(ntpin.rootdisp);
1001
1002                         if(debug)
1003                                 fprint(2, "ntp %s stratum %d ntpdelay(%lld)\n",
1004                                         ns->name, ntpin.stratum, ns->rtt);
1005                         return 0;
1006                 }
1007
1008                 /* try again */
1009                 sleep(250);
1010         }
1011         close(fd);
1012         return -1;
1013 }
1014
1015 static vlong
1016 gpssample(void)
1017 {
1018         vlong   l, g, d;
1019         int     i, n;
1020         char    *v[4], buf[128];
1021
1022         d = -1000000000000000000LL;
1023         for(i = 0; i < 5; i++){
1024                 sleep(1100);
1025                 seek(gpsfil, 0, 0);
1026                 n = read(gpsfil, buf, sizeof buf - 1);
1027                 if (n <= 0)
1028                         return 0;
1029                 buf[n] = 0;
1030                 n = tokenize(buf, v, nelem(v));
1031                 if(n != 4 || strcmp(v[3], "A") != 0)
1032                         return 0;
1033                 g = atoll(v[1]);
1034                 l = atoll(v[2]);
1035                 if(g-l > d)
1036                         d = g-l;
1037         }
1038         return d;
1039 }
1040
1041 static vlong
1042 ntpsample(void)
1043 {
1044         NTPserver *tns, *ns;
1045         vlong metric, x;
1046
1047         metric = 1000LL*SEC;
1048         ns = nil;
1049         for(tns = ntpservers; tns != nil; tns = tns->next){
1050                 if(ntptimediff(tns) < 0)
1051                         continue;
1052                 x = vabs(tns->rootdisp) + (vabs(tns->rtt+tns->rootdelay)>>1);
1053                 if(debug)
1054                         fprint(2, "ntp %s rootdelay %lld rootdisp %lld metric %lld\n",
1055                                 tns->name, tns->rootdelay, tns->rootdisp, x);
1056                 if(x < metric){
1057                         metric = x;
1058                         ns = tns;
1059                 }
1060         }
1061
1062         if(ns == nil)
1063                 return 0;
1064
1065         /* save data for our server */
1066         rootdisp = ns->rootdisp;
1067         rootdelay = ns->rootdelay;
1068         mydelay = ns->rtt;
1069         mydisp = avgerr;
1070         if(ns->stratum == 0)
1071                 stratum = 0;
1072         else
1073                 stratum = ns->stratum + 1;
1074
1075         ε = abs(ns->rtt/2);
1076         return ns->dt;
1077 }
1078
1079 /*
1080  * sample the utc file
1081  */
1082 static vlong
1083 utcsample(void)
1084 {
1085         vlong   s;
1086         int     n;
1087         char    *v[2], buf[128];
1088
1089         s = 0;
1090         seek(utcfil, 0, 0);
1091         n = read(utcfil, buf, sizeof buf - 1);
1092         if (n <= 0)
1093                 return 0;
1094         buf[n] = 0;
1095         n = tokenize(buf, v, nelem(v));
1096         if (strcmp(v[0], "0") == 0)
1097                 return 0;
1098         if (n == 2) {
1099                 gettime(&s, nil, nil);
1100                 s -= atoll(v[1]);
1101         }
1102         lastutc = atoll(v[0]) + s;
1103         return lastutc;
1104 }
1105
1106 /*
1107  *  sntp server
1108  */
1109 static int
1110 openlisten(char *net)
1111 {
1112         int fd, cfd;
1113         char data[128], devdir[40];
1114
1115         sprint(data, "%s/udp!*!ntp", net);
1116         cfd = announce(data, devdir);
1117         if(cfd < 0)
1118                 sysfatal("can't announce");
1119         if(fprint(cfd, "headers") < 0)
1120                 sysfatal("can't set header mode");
1121
1122         sprint(data, "%s/data", devdir);
1123         fd = open(data, ORDWR);
1124         if(fd < 0)
1125                 sysfatal("open %s: %r", data);
1126         return fd;
1127 }
1128
1129 static void
1130 ntpserver(char *servenet)
1131 {
1132         int fd, n, vers, mode;
1133         vlong recvts, x;
1134         char buf[512];
1135         NTPpkt *ntp;
1136
1137         fd = openlisten(servenet);
1138
1139         if (Rootid == nil)
1140                 switch(type){
1141                 case Fs:
1142                         Rootid = "WWV";
1143                         break;
1144                 case Rtc:
1145                         Rootid = "LOCL";
1146                         break;
1147                 case Utc:
1148                         Rootid = "UTC";
1149                         break;
1150                 case Gps:
1151                         Rootid = "GPS";
1152                         break;
1153                 case Ntp:
1154                         /* set by the ntp client */
1155                         break;
1156                 }
1157         if (Rootid != nil)
1158                 memmove(rootid, Rootid, strlen(Rootid) > 4? 4: strlen(Rootid));
1159
1160         for(;;){
1161                 n = read(fd, buf, sizeof buf);
1162                 gettime(&recvts, 0, 0);
1163                 if(n <= 0) {
1164                         /* don't croak on input error, but don't spin either */
1165                         sleep(500);
1166                         continue;
1167                 }
1168                 if(n < Udphdrsize + NTPSIZE)
1169                         continue;
1170
1171                 ntp = (NTPpkt*)(buf + Udphdrsize);
1172                 mode = ntp->mode & 7;
1173                 vers = (ntp->mode>>3) & 7;
1174                 if(mode != 3)
1175                         continue;
1176
1177                 ntp->mode = (vers<<3)|4;
1178                 ntp->stratum = stratum;
1179                 ntp->precision = myprec;
1180                 hnputfp(ntp->rootdelay, rootdelay + mydelay);
1181                 hnputfp(ntp->rootdisp, rootdisp + mydisp);
1182                 hnputts(ntp->refts, lastutc);
1183                 memmove(ntp->origts, ntp->xmitts, sizeof(ntp->origts));
1184                 hnputts(ntp->recvts, recvts);
1185                 memmove(ntp->rootid, rootid, sizeof(ntp->rootid));
1186                 gettime(&x, 0, 0);
1187                 hnputts(ntp->xmitts, x);
1188                 write(fd, buf, NTPSIZE + Udphdrsize);
1189         }
1190 }
1191
1192 /*
1193  *  get the current time from the file system
1194  */
1195 static long
1196 fstime(void)
1197 {
1198         Dir *d;
1199         ulong t;
1200
1201         d = dirstat("/n/boot");
1202         if(d != nil){
1203                 t = d->atime;
1204                 free(d);
1205         } else
1206                 t = 0;
1207         return t;
1208 }
1209
1210 /*
1211  *  get the current time from the real time clock
1212  */
1213 static long
1214 rtctime(void)
1215 {
1216         char b[20];
1217         static int f = -1;
1218         int i, retries;
1219
1220         memset(b, 0, sizeof(b));
1221         for(retries = 0; retries < 100; retries++){
1222                 if(f < 0)
1223                         f = open("/dev/rtc", OREAD|OCEXEC);
1224                 if(f < 0)
1225                         break;
1226                 if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof b)) < 0){
1227                         close(f);
1228                         f = -1;
1229                 } else
1230                         if(i != 0)
1231                                 break;
1232         }
1233         return strtoul(b, 0, 10)+gmtdelta;
1234 }
1235
1236
1237 /*
1238  *  Sample a clock.  We wait for the clock to always
1239  *  be at the leading edge of a clock period.
1240  */
1241 static vlong
1242 sample(long (*get)(void))
1243 {
1244         long this, last;
1245         vlong start, end;
1246
1247         /*
1248          *  wait for the second to change
1249          */
1250         last = (*get)();
1251         for(;;){
1252                 gettime(&start, 0, 0);
1253                 this = (*get)();
1254                 gettime(&end, 0, 0);
1255                 if(this != last)
1256                         break;
1257                 last = this;
1258         }
1259         return SEC*this - (end-start)/2;
1260 }
1261
1262 /*
1263  * the name of the frequency file has the method and possibly the
1264  * server name encoded in it.
1265  */
1266 static int
1267 openfreqfile(void)
1268 {
1269         char *p;
1270         int fd;
1271
1272         if(sysid == nil)
1273                 return -1;
1274
1275         switch(type){
1276         case Ntp:
1277                 p = smprint("%s/ts.%s.%d.%s", dir, sysid, type, timeserver);
1278                 break;
1279         default:
1280                 p = smprint("%s/ts.%s.%d", dir, sysid, type);
1281                 break;
1282         }
1283         fd = open(p, ORDWR);
1284         if(fd < 0)
1285                 fd = create(p, ORDWR, 0666);
1286         free(p);
1287         if(fd < 0)
1288                 return -1;
1289         return fd;
1290 }
1291
1292 /*
1293  *  the file contains the last known frequency and the
1294  *  number of seconds it was sampled over
1295  */
1296 static vlong
1297 readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz)
1298 {
1299         int n;
1300         char buf[128];
1301         vlong hz;
1302
1303         n = read(fd, buf, sizeof buf-1);
1304         if(n <= 0)
1305                 return ohz;
1306         buf[n] = 0;
1307         hz = strtoll(buf, nil, 0);
1308
1309         if(hz > maxhz || hz < minhz)
1310                 return ohz;
1311
1312         settime(-1, hz, 0, 0);
1313         return hz;
1314 }
1315
1316 /*
1317  *  remember hz and averaging period
1318  */
1319 static void
1320 writefreqfile(int fd, vlong hz, int secs, vlong diff)
1321 {
1322         long now;
1323         static long last;
1324
1325         if(fd < 0)
1326                 return;
1327         now = time(0);
1328         if(now - last < 10*60)
1329                 return;
1330         last = now;
1331         if(seek(fd, 0, 0) < 0)
1332                 return;
1333         fprint(fd, "%lld %d %d %lld\n", hz, secs, type, diff);
1334 }
1335
1336 static uvlong
1337 vabs(vlong x)
1338 {
1339         if(x < 0)
1340                 return -x;
1341         else
1342                 return x;
1343 }
1344
1345 static void
1346 background(void)
1347 {
1348         static int inbackground;
1349
1350         if(inbackground)
1351                 return;
1352
1353         if(!debug) 
1354                 switch(rfork(RFPROC|RFFDG|RFNAMEG|RFNOTEG|RFNOWAIT)){
1355                 case -1:
1356                         sysfatal("forking: %r");
1357                         break;
1358                 case 0:
1359                         break;
1360                 default:
1361                         exits(0);
1362                 }
1363         inbackground = 1;
1364 }
1365
1366 static int
1367 getclockprecision(vlong hz)
1368 {
1369         int i;
1370
1371         i = 8;
1372         while(hz > 0){
1373                 i--;
1374                 hz >>= 1;
1375         }
1376         return i;
1377 }