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