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