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