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