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