Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/aux/timesync.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <ip.h>
5
#include <mp.h>
6
 
7
/* nanosecond times */
8
#define SEC 1000000000LL
9
#define MIN (60LL*SEC)
10
#define HOUR (60LL*MIN)
11
#define DAY (24LL*HOUR)
12
 
13
enum {
14
	Fs,
15
	Rtc,
16
	Ntp,
17
	Utc,
18
	Gps,
19
 
20
	HZAvgSecs= 3*60,  /* target averaging period for frequency in seconds */
21
	MinSampleSecs= 60,	/* minimum sampling time in seconds */
22
};
23
 
24
 
25
char *dir = "/tmp";	/* directory sample files live in */
26
char *logfile = "timesync";
27
char *timeserver;
28
char *Rootid;
29
int utcfil;
30
int gpsfil;
31
int debug;
32
int impotent;
33
int logging;
34
int type;
35
int gmtdelta;		/* rtc+gmtdelta = gmt */
36
uvlong avgerr;
37
 
38
/* ntp server info */
39
int stratum = 14;
40
vlong mydisp, rootdisp;
41
vlong mydelay, rootdelay;
42
vlong avgdelay;
43
vlong lastutc;
44
uchar rootid[4];
45
char *sysid;
46
int myprec;
47
 
48
/* list of time samples */
49
typedef struct Sample Sample;
50
struct Sample
51
{
52
	Sample	*next;
53
	uvlong	ticks;
54
	vlong	ltime;
55
	vlong	stime;
56
};
57
 
58
/* ntp packet */
59
typedef struct NTPpkt NTPpkt;
60
struct NTPpkt
61
{
62
	uchar	mode;
63
	uchar	stratum;
64
	uchar	poll;
65
	uchar	precision;
66
	uchar	rootdelay[4];
67
	uchar	rootdisp[4];
68
	uchar	rootid[4];
69
	uchar	refts[8];
70
	uchar	origts[8];	/* departed client */
71
	uchar	recvts[8];	/* arrived at server */
72
	uchar	xmitts[8];	/* departed server */
73
	uchar	keyid[4];
74
	uchar	digest[16];
75
};
76
 
77
/* ntp server */
78
typedef struct NTPserver NTPserver;
79
struct NTPserver
80
{
81
	NTPserver *next;
82
	char	*name;
83
	uchar	stratum;
84
	uchar	precision;
85
	vlong	rootdelay;
86
	vlong	rootdisp;
87
	vlong	rtt;
88
	vlong	dt;
89
};
90
 
91
NTPserver *ntpservers;
92
 
93
enum
94
{
95
	NTPSIZE= 	48,	/* basic ntp packet */
96
	NTPDIGESTSIZE=	20,	/* key and digest */
97
};
98
 
99
/* error bound of last sample */
100
ulong	ε;
101
 
102
static void	addntpserver(char *name);
103
static int	adjustperiod(vlong diff, vlong accuracy, int secs);
104
static void	background(void);
105
static int	caperror(vlong dhz, int tsecs, vlong taccuracy);
106
static long	fstime(void);
107
static int	gettime(vlong *nsec, uvlong *ticks, uvlong *hz); /* returns time, ticks, hz */
108
static int	getclockprecision(vlong);
109
static vlong	gpssample(void);
110
static void	hnputts(void *p, vlong nsec);
111
static void	hnputts(void *p, vlong nsec);
112
static void	inittime(void);
113
static vlong	nhgetts(void *p);
114
static vlong	nhgetts(void *p);
115
static void	ntpserver(char*);
116
static vlong	ntpsample(void);
117
static int	ntptimediff(NTPserver *ns);
118
static int	openfreqfile(void);
119
static vlong	readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz);
120
static long	rtctime(void);
121
static vlong	sample(long (*get)(void));
122
static void	setpriority(void);
123
static void	setrootid(char *d);
124
static void	settime(vlong now, uvlong hz, vlong delta, int n); /* set time, hz, delta, period */
125
static vlong	utcsample(void);
126
static uvlong	vabs(vlong);
127
static uvlong	whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz,
128
			vlong dt, vlong ticks, vlong period);
129
static void	writefreqfile(int fd, vlong hz, int secs, vlong diff);
130
 
131
// ((1970-1900)*365 + 17 /*leap days*/)*24*60*60
132
#define EPOCHDIFF 2208988800UL
133
 
134
static void
135
usage(void)
136
{
137
	fprint(2, "usage: %s [-a accuracy][-d dir][-I rootid][-s net]"
138
		"[-S stratum][-DfGilLnrU] timesource ...\n", argv0);
139
	exits("usage");
140
}
141
 
142
void
143
main(int argc, char **argv)
144
{
145
	int i, t, fd, nservenet;
146
	int secs;		/* sampling period */
147
	int tsecs;		/* temporary sampling period */
148
	uvlong hz, minhz, maxhz, period, nhz;
149
	vlong diff, accuracy, taccuracy;
150
	char *servenet[4];
151
	Sample *s, *x, *first, **l;
152
	Tm tl, tg;
153
 
154
	type = Fs;		/* by default, sync with the file system */
155
	debug = 0;
156
	accuracy = 1000000LL;	/* default accuracy is 1 millisecond */
157
	nservenet = 0;
158
	tsecs = secs = MinSampleSecs;
159
	timeserver = "";
160
 
161
	ARGBEGIN{
162
	case 'a':
163
		accuracy = strtoll(EARGF(usage()), 0, 0); /* specified in ns */
164
		if(accuracy <= 1)
165
			sysfatal("bad accuracy specified");
166
		break;
167
	case 'd':
168
		dir = EARGF(usage());
169
		break;
170
	case 'D':
171
		debug = 1;
172
		break;
173
	case 'f':
174
		type = Fs;
175
		stratum = 2;
176
		break;
177
	case 'G':
178
		type = Gps;
179
		stratum = 1;
180
		break;
181
	case 'i':
182
		impotent = 1;
183
		break;
184
	case 'I':
185
		Rootid = EARGF(usage());
186
		break;
187
	case 'l':
188
		logging = 1;
189
		break;
190
	case 'L':
191
		/*
192
		 * Assume time source in local time rather than GMT.
193
		 * Calculate difference so that rtctime can return GMT.
194
		 * This is useful with the rtc on PC's that run Windows
195
		 * since Windows keeps the local time in the rtc.
196
		 */
197
		t = time(0);
198
		tl = *localtime(t);
199
		tg = *gmtime(t);
200
 
201
		/*
202
		 * if the years are different, we're at most a day off,
203
		 * so just rewrite
204
		 */
205
		if(tl.year < tg.year){
206
			tg.year--;
207
			tg.yday = tl.yday + 1;
208
		}else if(tl.year > tg.year){
209
			tl.year--;
210
			tl.yday = tg.yday+1;
211
		}
212
		assert(tl.year == tg.year);
213
 
214
		tg.sec -= tl.sec;
215
		tg.min -= tl.min;
216
		tg.hour -= tl.hour;
217
		tg.yday -= tl.yday;
218
		gmtdelta = tg.sec+60*(tg.min+60*(tg.hour+tg.yday*24));
219
 
220
		assert(abs(gmtdelta) <= 24*60*60);
221
		break;
222
	case 'n':
223
		type = Ntp;
224
		break;
225
	case 'r':
226
		type = Rtc;
227
		stratum = 0;
228
		break;
229
	case 'U':
230
		type = Utc;
231
		stratum = 1;
232
		break;
233
	case 's':
234
		if(nservenet >= nelem(servenet))
235
			sysfatal("too many networks to serve on");
236
		servenet[nservenet++] = EARGF(usage());
237
		break;
238
	case 'S':
239
		stratum = strtoll(EARGF(usage()), 0, 0);
240
		break;
241
	default:
242
		usage();
243
	}ARGEND;
244
 
245
	fmtinstall('E', eipfmt);
246
	fmtinstall('I', eipfmt);
247
	fmtinstall('V', eipfmt);
248
	sysid = getenv("sysname");
249
 
250
	/* detach from the current namespace */
251
	if(debug)
252
		rfork(RFNAMEG);
253
 
254
	switch(type){
255
	case Utc:
256
		if(argc > 0)
257
			timeserver = argv[0];
258
		else
259
			sysfatal("bad time source");
260
		break;
261
	case Gps:
262
		if(argc > 0)
263
			timeserver = argv[0];
264
		else
265
			timeserver = "/mnt/gps/time";
266
		break;
267
	case Fs:
268
		if(argc > 0)
269
			timeserver = argv[0];
270
		else
271
			timeserver = "/srv/boot";
272
		break;
273
	case Ntp:
274
		if(argc > 0)
275
			for(i = 0; i < argc; i++)
276
				addntpserver(argv[i]);
277
		else
278
			addntpserver("$ntp");
279
		break;
280
	}
281
 
282
	setpriority();
283
 
284
	/* figure out our time interface and initial frequency */
285
	inittime();
286
	gettime(0, 0, &hz);
287
	minhz = hz/10;
288
	maxhz = hz*10;
289
	myprec = getclockprecision(hz);
290
 
291
	/* convert the accuracy from nanoseconds to ticks */
292
	taccuracy = hz*accuracy/SEC;
293
 
294
	/*
295
	 * bind in clocks
296
	 */
297
	switch(type){
298
	case Fs:
299
		fd = open(timeserver, ORDWR);
300
		if(fd < 0)
301
			sysfatal("opening %s: %r", timeserver);
302
		if(amount(fd, "/n/boot", MREPL, "") < 0)
303
			sysfatal("mounting %s: %r", timeserver);
304
		close(fd);
305
		break;
306
	case Rtc:
307
		bind("#r", "/dev", MAFTER);
308
		if(access("/dev/rtc", AREAD) < 0)
309
			sysfatal("accessing /dev/rtc: %r");
310
		break;
311
	case Utc:
312
		fd = open(timeserver, OREAD);
313
		if(fd < 0)
314
			sysfatal("opening %s: %r", timeserver);
315
		utcfil = fd;
316
		break;
317
	case Gps:
318
		fd = open(timeserver, OREAD);
319
		if(fd < 0)
320
			sysfatal("opening %s: %r", timeserver);
321
		gpsfil = fd;
322
		break;
323
	}
324
 
325
	/*
326
	 * start a local ntp server(s)
327
	 */
328
	for(i = 0; i < nservenet; i++)
329
		switch(rfork(RFPROC|RFFDG|RFMEM|RFNOWAIT)){
330
		case -1:
331
			sysfatal("forking: %r");
332
		case 0:
333
			ntpserver(servenet[i]);
334
			_exits(0);
335
		}
336
 
337
	/* get the last known frequency from the file */
338
	fd = openfreqfile();
339
	hz = readfreqfile(fd, hz, minhz, maxhz);
340
 
341
	/*
342
	 * this is the main loop.  it gets a sample, adjusts the
343
	 * clock and computes a sleep period until the next loop.
344
	 * we balance frequency drift against the length of the
345
	 * period to avoid blowing the accuracy limit.
346
	 */
347
	first = nil;
348
	l = &first;
349
	avgerr = accuracy >> 1;
350
	for(;; background(), sleep(tsecs*1000)){
351
		s = mallocz(sizeof *s, 1);
352
		diff = 0;
353
 
354
		/* get times for this sample */
355
		ε = ~0;
356
		switch(type){
357
		case Fs:
358
			s->stime = sample(fstime);
359
			break;
360
		case Rtc:
361
			s->stime = sample(rtctime);
362
			break;
363
		case Utc:
364
			s->stime = utcsample();
365
			if(s->stime == 0LL){
366
				if(logging)
367
					syslog(0, logfile, "no sample");
368
				free(s);
369
				if (secs > 60 * 15)
370
					tsecs = 60*15;
371
				continue;
372
			}
373
			break;
374
		case Ntp:
375
			diff = ntpsample();
376
			if(diff == 0LL){
377
				if(logging)
378
					syslog(0, logfile, "no sample");
379
				free(s);
380
				if(secs > 60*15)
381
					tsecs = 60*15;
382
				continue;
383
			}
384
			break;
385
		case Gps:
386
			diff = gpssample();
387
			if(diff == 0LL){
388
				if(logging)
389
					syslog(0, logfile, "no sample");
390
				free(s);
391
				if(secs > 60*15)
392
					tsecs = 60*15;
393
				continue;
394
			}
395
		}
396
 
397
		/* use fastest method to read local clock and ticks */
398
		gettime(&s->ltime, &s->ticks, 0);
399
		if(type == Ntp || type == Gps)
400
			s->stime = s->ltime + diff;
401
 
402
		/* if the sample was bad, ignore it */
403
		if(s->stime < 0){
404
			free(s);
405
			continue;
406
		}
407
 
408
		/* reset local time */
409
		diff = s->stime - s->ltime;
410
		if(diff > 10*SEC || diff < -10*SEC){
411
			/* we're way off, just set the time */
412
			secs = MinSampleSecs;
413
			settime(s->stime, 0, 0, 0);
414
		} else {
415
			/* keep a running average of the error. */
416
			avgerr = (avgerr>>1) + (vabs(diff)>>1);
417
 
418
			/*
419
			 * the time to next sample depends on how good or
420
			 * bad we're doing.
421
			 */
422
			tsecs = secs = adjustperiod(diff, accuracy, secs);
423
 
424
			/*
425
			 * work off the fixed difference.  This is done
426
			 * by adding a ramp to the clock.  Each 100th of a
427
			 * second (or so) the kernel will add diff/(4*secs*100)
428
			 * to the clock.  we only do 1/4 of the difference per
429
			 * period to dampen any measurement noise.
430
			 *
431
			 * any difference greater than ε we work off during the
432
			 * sampling period.
433
			 */
434
			if(abs(diff) > ε)
435
				if(diff > 0)
436
					settime(-1, 0, diff-((3*ε)/4), secs);
437
				else
438
					settime(-1, 0, diff+((3*ε)/4), secs);
439
			else
440
				settime(-1, 0, diff, 4*secs);
441
 
442
		}
443
		if(debug)
444
			fprint(2, "δ %lld avgδ %lld f %lld\n", diff, avgerr, hz);
445
 
446
		/* dump old samples (keep at least one) */
447
		while(first != nil){
448
			if(first->next == nil)
449
				break;
450
			if(s->stime - first->next->stime < DAY)
451
				break;
452
			x = first;
453
			first = first->next;
454
			free(x);
455
		}
456
 
457
		/*
458
		 * The sampling error is limited by the total error.  If
459
		 * we make sure the sampling period is at least 16 million
460
		 * times the average error, we should calculate a frequency
461
		 * with on average a 1e-7 error.
462
		 *
463
		 * So that big hz changes don't blow our accuracy requirement,
464
		 * we shorten the period to make sure that δhz*secs will be
465
		 * greater than the accuracy limit.
466
		 */
467
		period = avgerr << 24;
468
		for(x = first; x != nil; x = x->next)
469
			if(s->stime - x->stime < period ||
470
			   x->next == nil || s->stime - x->next->stime < period)
471
				break;
472
		if(x != nil){
473
			nhz = whatisthefrequencykenneth(
474
				hz, minhz, maxhz,
475
				s->stime - x->stime,
476
				s->ticks - x->ticks,
477
				period);
478
			tsecs = caperror(vabs(nhz-hz), tsecs, taccuracy);
479
			hz = nhz;
480
			writefreqfile(fd, hz, (s->stime - x->stime)/SEC, diff);
481
		}
482
 
483
		/* add current sample to list. */
484
		*l = s;
485
		l = &s->next;
486
 
487
		if(logging)
488
			syslog(0, logfile, "δ %lld avgδ %lld hz %lld",
489
				diff, avgerr, hz);
490
	}
491
}
492
 
493
/*
494
 * adjust the sampling period with some histeresis
495
 */
496
static int
497
adjustperiod(vlong diff, vlong accuracy, int secs)
498
{
499
	uvlong absdiff;
500
 
501
	absdiff = vabs(diff);
502
 
503
	if(absdiff < (accuracy>>1))
504
		secs += 60;
505
	else if(absdiff > accuracy)
506
		secs >>= 1;
507
	else
508
		secs -= 60;
509
	if(secs < MinSampleSecs)
510
		secs = MinSampleSecs;
511
	return secs;
512
}
513
 
514
/*
515
 * adjust the frequency
516
 */
517
static uvlong
518
whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz, vlong dt,
519
	vlong ticks, vlong period)
520
{
521
	uvlong ohz = hz;
522
	static mpint *mpdt, *mpticks, *mphz, *mpbillion;
523
 
524
	/* sanity check */
525
	if(dt <= 0 || ticks <= 0)
526
		return hz;
527
 
528
	if(mphz == nil){
529
		mphz = mpnew(0);
530
		mpbillion = uvtomp(SEC, nil);
531
	}
532
 
533
	/* hz = (ticks*SEC)/dt */
534
	mpdt = vtomp(dt, mpdt);
535
	mpticks = vtomp(ticks, mpticks);
536
	mpmul(mpticks, mpbillion, mpticks);
537
	mpdiv(mpticks, mpdt, mphz, nil);
538
	hz = mptoui(mphz);
539
 
540
	/* sanity */
541
	if(hz < minhz || hz > maxhz)
542
		return ohz;
543
 
544
	/* damp the change if we're shorter than the target period */
545
	if(period > dt)
546
		hz = (12ULL*ohz + 4ULL*hz)/16ULL;
547
 
548
	settime(-1, hz, 0, 0);
549
	return hz;
550
}
551
 
552
/*
553
 * We may be changing the frequency to match a bad measurement
554
 * or to match a condition no longer in effect.  To make sure
555
 * that this doesn't blow our error budget over the next measurement
556
 * period, shorten the period to make sure that δhz*secs will be
557
 * less than the accuracy limit.  Here taccuracy is accuracy converted
558
 * from nanoseconds to ticks.
559
 */
560
static int
561
caperror(vlong dhz, int tsecs, vlong taccuracy)
562
{
563
	if(dhz*tsecs <= taccuracy)
564
		return tsecs;
565
 
566
	if(debug)
567
		fprint(2, "δhz %lld tsecs %d tacc %lld\n", dhz, tsecs, taccuracy);
568
 
569
	tsecs = taccuracy/dhz;
570
	if(tsecs < MinSampleSecs)
571
		tsecs = MinSampleSecs;
572
	return tsecs;
573
}
574
 
575
/*
576
 *  kernel interface
577
 */
578
enum
579
{
580
	Ibintime,
581
	Insec,
582
	Itiming,
583
};
584
int ifc;
585
int bintimefd = -1;
586
int timingfd = -1;
587
int nsecfd = -1;
588
int fastclockfd = -1;
589
 
590
static void
591
inittime(void)
592
{
593
	int mode;
594
 
595
	if(impotent)
596
		mode = OREAD;
597
	else
598
		mode = ORDWR;
599
 
600
	/* bind in clocks */
601
	if(access("/dev/time", 0) < 0)
602
		bind("#c", "/dev", MAFTER);
603
	if(access("/dev/rtc", 0) < 0)
604
		bind("#r", "/dev", MAFTER);
605
 
606
	/* figure out what interface we have */
607
	ifc = Ibintime;
608
	bintimefd = open("/dev/bintime", mode);
609
	if(bintimefd >= 0)
610
		return;
611
	ifc = Insec;
612
	nsecfd = open("/dev/nsec", mode);
613
	if(nsecfd < 0)
614
		sysfatal("opening /dev/nsec");
615
	fastclockfd = open("/dev/fastclock", mode);
616
	if(fastclockfd < 0)
617
		sysfatal("opening /dev/fastclock");
618
	timingfd = open("/dev/timing", OREAD);
619
	if(timingfd < 0)
620
		return;
621
	ifc = Itiming;
622
}
623
 
624
/*
625
 *  convert binary numbers from/to kernel
626
 */
627
static uvlong uvorder = 0x0001020304050607ULL;
628
 
629
static uchar*
630
be2vlong(vlong *to, uchar *f)
631
{
632
	uchar *t, *o;
633
	int i;
634
 
635
	t = (uchar*)to;
636
	o = (uchar*)&uvorder;
637
	for(i = 0; i < sizeof(vlong); i++)
638
		t[o[i]] = f[i];
639
	return f+sizeof(vlong);
640
}
641
 
642
static uchar*
643
vlong2be(uchar *t, vlong from)
644
{
645
	uchar *f, *o;
646
	int i;
647
 
648
	f = (uchar*)&from;
649
	o = (uchar*)&uvorder;
650
	for(i = 0; i < sizeof(vlong); i++)
651
		t[i] = f[o[i]];
652
	return t+sizeof(vlong);
653
}
654
 
655
static long order = 0x00010203;
656
 
657
static uchar*
658
be2long(long *to, uchar *f)
659
{
660
	uchar *t, *o;
661
	int i;
662
 
663
	t = (uchar*)to;
664
	o = (uchar*)&order;
665
	for(i = 0; i < sizeof(long); i++)
666
		t[o[i]] = f[i];
667
	return f+sizeof(long);
668
}
669
 
670
static uchar*
671
long2be(uchar *t, long from)
672
{
673
	uchar *f, *o;
674
	int i;
675
 
676
	f = (uchar*)&from;
677
	o = (uchar*)&order;
678
	for(i = 0; i < sizeof(long); i++)
679
		t[i] = f[o[i]];
680
	return t+sizeof(long);
681
}
682
 
683
/*
684
 * read ticks and local time in nanoseconds
685
 */
686
static int
687
gettime(vlong *nsec, uvlong *ticks, uvlong *hz)
688
{
689
	int i, n;
690
	uchar ub[3*8], *p;
691
	char b[2*24+1];
692
 
693
	switch(ifc){
694
	case Ibintime:
695
		n = sizeof(vlong);
696
		if(hz != nil)
697
			n = 3*sizeof(vlong);
698
		if(ticks != nil)
699
			n = 2*sizeof(vlong);
700
		i = read(bintimefd, ub, n);
701
		if(i != n)
702
			break;
703
		p = ub;
704
		if(nsec != nil)
705
			be2vlong(nsec, ub);
706
		p += sizeof(vlong);
707
		if(ticks != nil)
708
			be2vlong((vlong*)ticks, p);
709
		p += sizeof(vlong);
710
		if(hz != nil)
711
			be2vlong((vlong*)hz, p);
712
		return 0;
713
	case Itiming:
714
		n = sizeof(vlong);
715
		if(ticks != nil)
716
			n = 2*sizeof(vlong);
717
		i = read(timingfd, ub, n);
718
		if(i != n)
719
			break;
720
		p = ub;
721
		if(nsec != nil)
722
			be2vlong(nsec, ub);
723
		p += sizeof(vlong);
724
		if(ticks != nil)
725
			be2vlong((vlong*)ticks, p);
726
		if(hz != nil){
727
			seek(fastclockfd, 0, 0);
728
			n = read(fastclockfd, b, sizeof(b)-1);
729
			if(n <= 0)
730
				break;
731
			b[n] = 0;
732
			*hz = strtoll(b+24, 0, 0);
733
		}
734
		return 0;
735
	case Insec:
736
		if(nsec != nil){
737
			seek(nsecfd, 0, 0);
738
			n = read(nsecfd, b, sizeof(b)-1);
739
			if(n <= 0)
740
				break;
741
			b[n] = 0;
742
			*nsec = strtoll(b, 0, 0);
743
		}
744
		if(ticks != nil){
745
			seek(fastclockfd, 0, 0);
746
			n = read(fastclockfd, b, sizeof(b)-1);
747
			if(n <= 0)
748
				break;
749
			b[n] = 0;
750
			*ticks = strtoll(b, 0, 0);
751
		}
752
		if(hz != nil){
753
			seek(fastclockfd, 0, 0);
754
			n = read(fastclockfd, b, sizeof(b)-1);
755
			if(n <= 24)
756
				break;
757
			b[n] = 0;
758
			*hz = strtoll(b+24, 0, 0);
759
		}
760
		return 0;
761
	}
762
	return -1;
763
}
764
 
765
static void
766
settime(vlong now, uvlong hz, vlong delta, int n)
767
{
768
	uchar b[1+sizeof(vlong)+sizeof(long)], *p;
769
 
770
	if(debug)
771
		fprint(2, "settime(now=%lld, hz=%llud, delta=%lld, period=%d)\n",
772
			now, hz, delta, n);
773
	if(impotent)
774
		return;
775
	switch(ifc){
776
	case Ibintime:
777
		if(now >= 0){
778
			p = b;
779
			*p++ = 'n';
780
			p = vlong2be(p, now);
781
			if(write(bintimefd, b, p-b) < 0)
782
				sysfatal("writing /dev/bintime: %r");
783
		}
784
		if(delta != 0){
785
			p = b;
786
			*p++ = 'd';
787
			p = vlong2be(p, delta);
788
			p = long2be(p, n);
789
			if(write(bintimefd, b, p-b) < 0)
790
				sysfatal("writing /dev/bintime: %r");
791
		}
792
		if(hz != 0){
793
			p = b;
794
			*p++ = 'f';
795
			p = vlong2be(p, hz);
796
			if(write(bintimefd, b, p-b) < 0)
797
				sysfatal("writing /dev/bintime: %r");
798
		}
799
		break;
800
	case Itiming:
801
	case Insec:
802
		seek(nsecfd, 0, 0);
803
		if(now >= 0 || delta != 0){
804
			if(fprint(nsecfd, "%lld %lld %d", now, delta, n) < 0)
805
				sysfatal("writing /dev/nsec: %r");
806
		}
807
		if(hz > 0){
808
			seek(fastclockfd, 0, 0);
809
			if(fprint(fastclockfd, "%lld", hz) < 0)
810
				sysfatal("writing /dev/fastclock: %r");
811
		}
812
	}
813
}
814
 
815
/*
816
 *  set priority high and wire process to a processor
817
 */
818
static void
819
setpriority(void)
820
{
821
	int fd;
822
	char buf[32];
823
 
824
	sprint(buf, "/proc/%d/ctl", getpid());
825
	fd = open(buf, ORDWR);
826
	if(fd < 0){
827
		fprint(2, "can't set priority\n");
828
		return;
829
	}
830
	if(fprint(fd, "pri 100") < 0)
831
		fprint(2, "can't set priority\n");
832
	if(fprint(fd, "wired 2") < 0)
833
		fprint(2, "can't wire process\n");
834
	close(fd);
835
}
836
 
837
/* convert to ntp timestamps */
838
static void
839
hnputts(void *p, vlong nsec)
840
{
841
	uchar *a;
842
	ulong tsh, tsl;
843
 
844
	a = p;
845
 
846
	/* zero is a special case */
847
	if(nsec == 0)
848
		return;
849
 
850
	tsh = nsec/SEC;
851
	nsec -= tsh*SEC;
852
	tsl = (nsec<<32)/SEC;
853
	hnputl(a, tsh+EPOCHDIFF);
854
	hnputl(a+4, tsl);
855
}
856
 
857
/* convert from ntp timestamps */
858
static vlong
859
nhgetts(void *p)
860
{
861
	uchar *a;
862
	ulong tsh, tsl;
863
	vlong nsec;
864
 
865
	a = p;
866
	tsh = nhgetl(a);
867
	tsl = nhgetl(a+4);
868
	nsec = tsl*SEC;
869
	nsec >>= 32;
870
	nsec += (tsh - EPOCHDIFF)*SEC;
871
	return nsec;
872
}
873
 
874
/* convert to ntp 32 bit fixed point */
875
static void
876
hnputfp(void *p, vlong nsec)
877
{
878
	uchar *a;
879
	ulong fp;
880
 
881
	a = p;
882
 
883
	fp = nsec/(SEC/((vlong)(1<<16)));
884
	hnputl(a, fp);
885
}
886
 
887
/* convert from ntp fixed point to nanosecs */
888
static vlong
889
nhgetfp(void *p)
890
{
891
	uchar *a;
892
	ulong fp;
893
	vlong nsec;
894
 
895
	a = p;
896
	fp = nhgetl(a);
897
	nsec = ((vlong)fp)*(SEC/((vlong)(1<<16)));
898
	return nsec;
899
}
900
 
901
/* get network address of the server */
902
static void
903
setrootid(char *d)
904
{
905
	char buf[128];
906
	int fd, n;
907
	char *p;
908
 
909
	snprint(buf, sizeof buf, "%s/remote", d);
910
	fd = open(buf, OREAD);
911
	if(fd < 0)
912
		return;
913
	n = read(fd, buf, sizeof buf);
914
	close(fd);
915
	if(n <= 0)
916
		return;
917
	p = strchr(buf, '!');
918
	if(p != nil)
919
		*p = 0;
920
	v4parseip(rootid, buf);
921
}
922
 
923
static void
924
ding(void*, char *s)
925
{
926
	if(strstr(s, "alarm") != nil)
927
		noted(NCONT);
928
	noted(NDFLT);
929
}
930
 
931
static void
932
addntpserver(char *name)
933
{
934
	NTPserver *ns, **l;
935
 
936
	ns = mallocz(sizeof(NTPserver), 1);
937
	if(ns == nil)
938
		sysfatal("addntpserver: %r");
939
	timeserver = strdup(name);
940
	ns->name = name;
941
	for(l = &ntpservers; *l != nil; l = &(*l)->next)
942
		;
943
	*l = ns;
944
}
945
 
946
/*
947
 *  sntp client, we keep calling if the delay seems
948
 *  unusually high, i.e., 30% longer than avg.
949
 */
950
static int
951
ntptimediff(NTPserver *ns)
952
{
953
	int fd, tries, n;
954
	NTPpkt ntpin, ntpout;
955
	vlong dt, recvts, origts, xmitts, destts, x;
956
	char dir[64];
957
	static int whined;
958
 
959
	notify(ding);
960
	alarm(30*1000);	/* don't wait forever if ns->name is unreachable */
961
	fd = dial(netmkaddr(ns->name, "udp", "ntp"), 0, dir, 0);
962
	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
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
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
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
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
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
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
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
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
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
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
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
1338
vabs(vlong x)
1339
{
1340
	if(x < 0)
1341
		return -x;
1342
	else
1343
		return x;
1344
}
1345
 
1346
static 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
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
}