1/*- 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35#if 0 36static char sccsid[] = "@(#)master.c 8.1 (Berkeley) 6/6/93"; 37#endif 38__attribute__((__used__)) 39static const char rcsid[] = 40 "$FreeBSD: src/usr.sbin/timed/timed/master.c,v 1.10 2007/11/07 10:53:41 kevlo Exp $"; 41#endif /* not lint */ 42#include <sys/cdefs.h> 43 44#include "globals.h" 45#include <sys/file.h> 46#include <sys/types.h> 47#include <sys/times.h> 48#include <setjmp.h> 49#ifdef __APPLE__ 50#include <utmpx.h> 51#endif 52#include "pathnames.h" 53 54extern int measure_delta; 55extern jmp_buf jmpenv; 56extern int Mflag; 57extern int justquit; 58 59static int dictate; 60static int slvcount; /* slaves listening to our clock */ 61 62static void mchgdate(struct tsp *); 63 64#ifndef __APPLE__ 65extern void logwtmp(char *, char *, char *); 66#endif 67 68/* 69 * The main function of `master' is to periodically compute the differences 70 * (deltas) between its clock and the clocks of the slaves, to compute the 71 * network average delta, and to send to the slaves the differences between 72 * their individual deltas and the network delta. 73 * While waiting, it receives messages from the slaves (i.e. requests for 74 * master's name, remote requests to set the network time, ...), and 75 * takes the appropriate action. 76 */ 77int 78master() 79{ 80 struct hosttbl *htp; 81 long pollingtime; 82#define POLLRATE 4 83 int polls; 84 struct timeval wait, ntime; 85 time_t tsp_time_sec; 86 struct tsp *msg, *answer, to; 87 char newdate[32]; 88 struct sockaddr_in taddr; 89 char tname[MAXHOSTNAMELEN]; 90 struct netinfo *ntp; 91 int i; 92 93 syslog(LOG_NOTICE, "This machine is master"); 94 if (trace) 95 fprintf(fd, "This machine is master\n"); 96 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 97 if (ntp->status == MASTER) 98 masterup(ntp); 99 } 100 (void)gettimeofday(&ntime, 0); 101 pollingtime = ntime.tv_sec+3; 102 if (justquit) 103 polls = 0; 104 else 105 polls = POLLRATE-1; 106 107/* Process all outstanding messages before spending the long time necessary 108 * to update all timers. 109 */ 110loop: 111 (void)gettimeofday(&ntime, 0); 112 wait.tv_sec = pollingtime - ntime.tv_sec; 113 if (wait.tv_sec < 0) 114 wait.tv_sec = 0; 115 wait.tv_usec = 0; 116 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); 117 if (!msg) { 118 (void)gettimeofday(&ntime, 0); 119 if (ntime.tv_sec >= pollingtime) { 120 pollingtime = ntime.tv_sec + SAMPLEINTVL; 121 get_goodgroup(0); 122 123/* If a bogus master told us to quit, we can have decided to ignore a 124 * network. Therefore, periodically try to take over everything. 125 */ 126 polls = (polls + 1) % POLLRATE; 127 if (0 == polls && nignorednets > 0) { 128 trace_msg("Looking for nets to re-master\n"); 129 for (ntp = nettab; ntp; ntp = ntp->next) { 130 if (ntp->status == IGNORE 131 || ntp->status == NOMASTER) { 132 lookformaster(ntp); 133 if (ntp->status == MASTER) { 134 masterup(ntp); 135 polls = POLLRATE-1; 136 } 137 } 138 if (ntp->status == MASTER 139 && --ntp->quit_count < 0) 140 ntp->quit_count = 0; 141 } 142 if (polls != 0) 143 setstatus(); 144 } 145 146 synch(0L); 147 148 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 149 to.tsp_type = TSP_LOOP; 150 to.tsp_vers = TSPVERSION; 151 to.tsp_seq = sequence++; 152 to.tsp_hopcnt = MAX_HOPCNT; 153 (void)strcpy(to.tsp_name, hostname); 154 bytenetorder(&to); 155 if (sendto(sock, (char *)&to, 156 sizeof(struct tsp), 0, 157 (struct sockaddr*)&ntp->dest_addr, 158 sizeof(ntp->dest_addr)) < 0) { 159 trace_sendto_err(ntp->dest_addr.sin_addr); 160 } 161 } 162 } 163 164 165 } else { 166 switch (msg->tsp_type) { 167 168 case TSP_MASTERREQ: 169 break; 170 171 case TSP_SLAVEUP: 172 newslave(msg); 173 break; 174 175 case TSP_SETDATE: 176 /* 177 * XXX check to see it is from ourself 178 */ 179 tsp_time_sec = msg->tsp_time.tv_sec; 180 (void)strcpy(newdate, ctime(&tsp_time_sec)); 181 if (!good_host_name(msg->tsp_name)) { 182 syslog(LOG_NOTICE, 183 "attempted date change by %s to %s", 184 msg->tsp_name, newdate); 185 spreadtime(); 186 break; 187 } 188 189 mchgdate(msg); 190 (void)gettimeofday(&ntime, 0); 191 pollingtime = ntime.tv_sec + SAMPLEINTVL; 192 break; 193 194 case TSP_SETDATEREQ: 195 if (!fromnet || fromnet->status != MASTER) 196 break; 197 tsp_time_sec = msg->tsp_time.tv_sec; 198 (void)strcpy(newdate, ctime(&tsp_time_sec)); 199 htp = findhost(msg->tsp_name); 200 if (htp == 0) { 201 syslog(LOG_ERR, 202 "attempted SET DATEREQ by uncontrolled %s to %s", 203 msg->tsp_name, newdate); 204 break; 205 } 206 if (htp->seq == msg->tsp_seq) 207 break; 208 htp->seq = msg->tsp_seq; 209 if (!htp->good) { 210 syslog(LOG_NOTICE, 211 "attempted SET DATEREQ by untrusted %s to %s", 212 msg->tsp_name, newdate); 213 spreadtime(); 214 break; 215 } 216 217 mchgdate(msg); 218 (void)gettimeofday(&ntime, 0); 219 pollingtime = ntime.tv_sec + SAMPLEINTVL; 220 break; 221 222 case TSP_MSITE: 223 xmit(TSP_ACK, msg->tsp_seq, &from); 224 break; 225 226 case TSP_MSITEREQ: 227 break; 228 229 case TSP_TRACEON: 230 traceon(); 231 break; 232 233 case TSP_TRACEOFF: 234 traceoff("Tracing ended at %s\n"); 235 break; 236 237 case TSP_ELECTION: 238 if (!fromnet) 239 break; 240 if (fromnet->status == MASTER) { 241 pollingtime = 0; 242 (void)addmach(msg->tsp_name, &from,fromnet); 243 } 244 taddr = from; 245 (void)strcpy(tname, msg->tsp_name); 246 to.tsp_type = TSP_QUIT; 247 (void)strcpy(to.tsp_name, hostname); 248 answer = acksend(&to, &taddr, tname, 249 TSP_ACK, 0, 1); 250 if (answer == NULL) { 251 syslog(LOG_ERR, "election error by %s", 252 tname); 253 } 254 break; 255 256 case TSP_CONFLICT: 257 /* 258 * After a network partition, there can be 259 * more than one master: the first slave to 260 * come up will notify here the situation. 261 */ 262 if (!fromnet || fromnet->status != MASTER) 263 break; 264 (void)strcpy(to.tsp_name, hostname); 265 266 /* The other master often gets into the same state, 267 * with boring results if we stay at it forever. 268 */ 269 ntp = fromnet; /* (acksend() can leave fromnet=0 */ 270 for (i = 0; i < 3; i++) { 271 to.tsp_type = TSP_RESOLVE; 272 (void)strcpy(to.tsp_name, hostname); 273 answer = acksend(&to, &ntp->dest_addr, 274 ANYADDR, TSP_MASTERACK, 275 ntp, 0); 276 if (!answer) 277 break; 278 htp = addmach(answer->tsp_name,&from,ntp); 279 to.tsp_type = TSP_QUIT; 280 msg = acksend(&to, &htp->addr, htp->name, 281 TSP_ACK, 0, htp->noanswer); 282 if (msg == NULL) { 283 syslog(LOG_ERR, 284 "no response from %s to CONFLICT-QUIT", 285 htp->name); 286 } 287 } 288 masterup(ntp); 289 pollingtime = 0; 290 break; 291 292 case TSP_RESOLVE: 293 if (!fromnet || fromnet->status != MASTER) 294 break; 295 /* 296 * do not want to call synch() while waiting 297 * to be killed! 298 */ 299 (void)gettimeofday(&ntime, (struct timezone *)0); 300 pollingtime = ntime.tv_sec + SAMPLEINTVL; 301 break; 302 303 case TSP_QUIT: 304 doquit(msg); /* become a slave */ 305 break; 306 307 case TSP_LOOP: 308 if (!fromnet || fromnet->status != MASTER 309 || !strcmp(msg->tsp_name, hostname)) 310 break; 311 /* 312 * We should not have received this from a net 313 * we are master on. There must be two masters. 314 */ 315 htp = addmach(msg->tsp_name, &from,fromnet); 316 to.tsp_type = TSP_QUIT; 317 (void)strcpy(to.tsp_name, hostname); 318 answer = acksend(&to, &htp->addr, htp->name, 319 TSP_ACK, 0, 1); 320 if (!answer) { 321 syslog(LOG_WARNING, 322 "loop breakage: no reply from %s=%s to QUIT", 323 htp->name, inet_ntoa(htp->addr.sin_addr)); 324 (void)remmach(htp); 325 } 326 327 case TSP_TEST: 328 if (trace) { 329 fprintf(fd, 330 "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n", 331 nnets, nmasternets, nslavenets, nignorednets); 332 setstatus(); 333 } 334 pollingtime = 0; 335 polls = POLLRATE-1; 336 break; 337 338 default: 339 if (trace) { 340 fprintf(fd, "garbage message: "); 341 print(msg, &from); 342 } 343 break; 344 } 345 } 346 goto loop; 347 return 0; 348} 349 350 351/* 352 * change the system date on the master 353 */ 354static void 355mchgdate(msg) 356 struct tsp *msg; 357{ 358 char tname[MAXHOSTNAMELEN]; 359 char olddate[32]; 360 struct timeval otime, ntime, tmptv; 361 362 (void)strcpy(tname, msg->tsp_name); 363 364 xmit(TSP_DATEACK, msg->tsp_seq, &from); 365 366 (void)strcpy(olddate, date()); 367 368 /* adjust time for residence on the queue */ 369 (void)gettimeofday(&otime, 0); 370 adj_msg_time(msg,&otime); 371 372 tmptv.tv_sec = msg->tsp_time.tv_sec; 373 tmptv.tv_usec = msg->tsp_time.tv_usec; 374 timevalsub(&ntime, &tmptv, &otime); 375 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { 376 /* 377 * do not change the clock if we can adjust it 378 */ 379 dictate = 3; 380 synch(tvtomsround(ntime)); 381 } else { 382#ifdef __APPLE__ 383 // rdar://problem/4433603 384 struct utmpx u; 385 bzero(&u, sizeof(u)); 386 u.ut_type = OLD_TIME; 387 u.ut_tv = otime; 388 pututxline(&u); 389 u.ut_type = NEW_TIME; 390 u.ut_tv.tv_sec = msg->tsp_time.tv_sec; 391 u.ut_tv.tv_usec = msg->tsp_time.tv_usec; 392 (void)settimeofday(&u.ut_tv, 0); 393 pututxline(&u); 394#else /* !__APPLE__ */ 395 logwtmp("|", "date", ""); 396 (void)settimeofday(&tmptv, 0); 397 logwtmp("{", "date", ""); 398#endif /* __APPLE__ */ 399 spreadtime(); 400 } 401 402 syslog(LOG_NOTICE, "date changed by %s from %s", 403 tname, olddate); 404} 405 406 407/* 408 * synchronize all of the slaves 409 */ 410void 411synch(mydelta) 412 long mydelta; 413{ 414 struct hosttbl *htp; 415 int measure_status; 416 struct timeval check, stop, wait; 417 418 if (slvcount > 0) { 419 if (trace) 420 fprintf(fd, "measurements starting at %s\n", date()); 421 (void)gettimeofday(&check, 0); 422 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 423 if (htp->noanswer != 0) { 424 measure_status = measure(500, 100, 425 htp->name, 426 &htp->addr,0); 427 } else { 428 measure_status = measure(3000, 100, 429 htp->name, 430 &htp->addr,0); 431 } 432 if (measure_status != GOOD) { 433 /* The slave did not respond. We have 434 * just wasted lots of time on it. 435 */ 436 htp->delta = HOSTDOWN; 437 if (++htp->noanswer >= LOSTHOST) { 438 if (trace) { 439 fprintf(fd, 440 "purging %s for not answering ICMP\n", 441 htp->name); 442 (void)fflush(fd); 443 } 444 htp = remmach(htp); 445 } 446 } else { 447 htp->delta = measure_delta; 448 } 449 (void)gettimeofday(&stop, 0); 450 timevalsub(&stop, &stop, &check); 451 if (stop.tv_sec >= 1) { 452 if (trace) 453 (void)fflush(fd); 454 /* 455 * ack messages periodically 456 */ 457 wait.tv_sec = 0; 458 wait.tv_usec = 0; 459 if (0 != readmsg(TSP_TRACEON,ANYADDR, 460 &wait,0)) 461 traceon(); 462 (void)gettimeofday(&check, 0); 463 } 464 } 465 if (trace) 466 fprintf(fd, "measurements finished at %s\n", date()); 467 } 468 if (!(status & SLAVE)) { 469 if (!dictate) { 470 mydelta = networkdelta(); 471 } else { 472 dictate--; 473 } 474 } 475 if (trace && (mydelta != 0 || (status & SLAVE))) 476 fprintf(fd,"local correction of %ld ms.\n", mydelta); 477 correct(mydelta); 478} 479 480/* 481 * sends the time to each slave after the master 482 * has received the command to set the network time 483 */ 484void 485spreadtime() 486{ 487 struct hosttbl *htp; 488 struct tsp to; 489 struct tsp *answer; 490 struct timeval tmptv; 491 492/* Do not listen to the consensus after forcing the time. This is because 493 * the consensus takes a while to reach the time we are dictating. 494 */ 495 dictate = 2; 496 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 497 to.tsp_type = TSP_SETTIME; 498 (void)strcpy(to.tsp_name, hostname); 499 (void)gettimeofday(&tmptv, 0); 500 to.tsp_time.tv_sec = tmptv.tv_sec; 501 to.tsp_time.tv_usec = tmptv.tv_usec; 502 answer = acksend(&to, &htp->addr, htp->name, 503 TSP_ACK, 0, htp->noanswer); 504 if (answer == 0) { 505 /* We client does not respond, then we have 506 * just wasted lots of time on it. 507 */ 508 syslog(LOG_WARNING, 509 "no reply to SETTIME from %s", htp->name); 510 if (++htp->noanswer >= LOSTHOST) { 511 if (trace) { 512 fprintf(fd, 513 "purging %s for not answering", 514 htp->name); 515 (void)fflush(fd); 516 } 517 htp = remmach(htp); 518 } 519 } 520 } 521} 522 523void 524prthp(delta) 525 clock_t delta; 526{ 527 static time_t next_time; 528 time_t this_time; 529 struct tms tm; 530 struct hosttbl *htp; 531 int length, l; 532 int i; 533 534 if (!fd) /* quit if tracing already off */ 535 return; 536 537 this_time = times(&tm); 538 if ((time_t)(this_time + delta) < next_time) 539 return; 540 next_time = this_time + CLK_TCK; 541 542 fprintf(fd, "host table: %d entries at %s\n", slvcount, date()); 543 htp = self.l_fwd; 544 length = 1; 545 for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) { 546 l = strlen(htp->name) + 1; 547 if (length+l >= 80) { 548 fprintf(fd, "\n"); 549 length = 0; 550 } 551 length += l; 552 fprintf(fd, " %s", htp->name); 553 } 554 fprintf(fd, "\n"); 555} 556 557 558static struct hosttbl *newhost_hash; 559static struct hosttbl *lasthfree = &hosttbl[0]; 560 561 562struct hosttbl * /* answer or 0 */ 563findhost(name) 564 char *name; 565{ 566 int i, j; 567 struct hosttbl *htp; 568 char *p; 569 570 j= 0; 571 for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++) 572 j = (j << 2) ^ *p; 573 newhost_hash = &hosttbl[j % NHOSTS]; 574 575 htp = newhost_hash; 576 if (htp->name[0] == '\0') 577 return(0); 578 do { 579 if (!strcmp(name, htp->name)) 580 return(htp); 581 htp = htp->h_fwd; 582 } while (htp != newhost_hash); 583 return(0); 584} 585 586/* 587 * add a host to the list of controlled machines if not already there 588 */ 589struct hosttbl * 590addmach(name, addr, ntp) 591 char *name; 592 struct sockaddr_in *addr; 593 struct netinfo *ntp; 594{ 595 struct hosttbl *ret, *p, *b, *f; 596 597 ret = findhost(name); 598 if (ret == 0) { 599 if (slvcount >= NHOSTS) { 600 if (trace) { 601 fprintf(fd, "no more slots in host table\n"); 602 prthp(CLK_TCK); 603 } 604 syslog(LOG_ERR, "no more slots in host table"); 605 Mflag = 0; 606 longjmp(jmpenv, 2); /* give up and be a slave */ 607 } 608 609 /* if our home hash slot is occupied, find a free entry 610 * in the hash table 611 */ 612 if (newhost_hash->name[0] != '\0') { 613 do { 614 ret = lasthfree; 615 if (++lasthfree > &hosttbl[NHOSTS]) 616 lasthfree = &hosttbl[1]; 617 } while (ret->name[0] != '\0'); 618 619 if (!newhost_hash->head) { 620 /* Move an interloper using our home. Use 621 * scratch pointers in case the new head is 622 * pointing to itself. 623 */ 624 f = newhost_hash->h_fwd; 625 b = newhost_hash->h_bak; 626 f->h_bak = ret; 627 b->h_fwd = ret; 628 f = newhost_hash->l_fwd; 629 b = newhost_hash->l_bak; 630 f->l_bak = ret; 631 b->l_fwd = ret; 632 bcopy(newhost_hash,ret,sizeof(*ret)); 633 ret = newhost_hash; 634 ret->head = 1; 635 ret->h_fwd = ret; 636 ret->h_bak = ret; 637 } else { 638 /* link to an existing chain in our home 639 */ 640 ret->head = 0; 641 p = newhost_hash->h_bak; 642 ret->h_fwd = newhost_hash; 643 ret->h_bak = p; 644 p->h_fwd = ret; 645 newhost_hash->h_bak = ret; 646 } 647 } else { 648 ret = newhost_hash; 649 ret->head = 1; 650 ret->h_fwd = ret; 651 ret->h_bak = ret; 652 } 653 ret->addr = *addr; 654 ret->ntp = ntp; 655 (void)strncpy(ret->name, name, sizeof(ret->name)); 656 ret->good = good_host_name(name); 657 ret->l_fwd = &self; 658 ret->l_bak = self.l_bak; 659 self.l_bak->l_fwd = ret; 660 self.l_bak = ret; 661 slvcount++; 662 663 ret->noanswer = 0; 664 ret->need_set = 1; 665 666 } else { 667 ret->noanswer = (ret->noanswer != 0); 668 } 669 670 /* need to clear sequence number anyhow */ 671 ret->seq = 0; 672 return(ret); 673} 674 675/* 676 * remove the machine with the given index in the host table. 677 */ 678struct hosttbl * 679remmach(htp) 680 struct hosttbl *htp; 681{ 682 struct hosttbl *lprv, *hnxt, *f, *b; 683 684 if (trace) 685 fprintf(fd, "remove %s\n", htp->name); 686 687 /* get out of the lists */ 688 htp->l_fwd->l_bak = lprv = htp->l_bak; 689 htp->l_bak->l_fwd = htp->l_fwd; 690 htp->h_fwd->h_bak = htp->h_bak; 691 htp->h_bak->h_fwd = hnxt = htp->h_fwd; 692 693 /* If we are in the home slot, pull up the chain */ 694 if (htp->head && hnxt != htp) { 695 if (lprv == hnxt) 696 lprv = htp; 697 698 /* Use scratch pointers in case the new head is pointing to 699 * itself. 700 */ 701 f = hnxt->h_fwd; 702 b = hnxt->h_bak; 703 f->h_bak = htp; 704 b->h_fwd = htp; 705 f = hnxt->l_fwd; 706 b = hnxt->l_bak; 707 f->l_bak = htp; 708 b->l_fwd = htp; 709 hnxt->head = 1; 710 bcopy(hnxt, htp, sizeof(*htp)); 711 lasthfree = hnxt; 712 } else { 713 lasthfree = htp; 714 } 715 716 lasthfree->name[0] = '\0'; 717 lasthfree->h_fwd = 0; 718 lasthfree->l_fwd = 0; 719 slvcount--; 720 721 return lprv; 722} 723 724 725/* 726 * Remove all the machines from the host table that exist on the given 727 * network. This is called when a master transitions to a slave on a 728 * given network. 729 */ 730void 731rmnetmachs(ntp) 732 struct netinfo *ntp; 733{ 734 struct hosttbl *htp; 735 736 if (trace) 737 prthp(CLK_TCK); 738 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 739 if (ntp == htp->ntp) 740 htp = remmach(htp); 741 } 742 if (trace) 743 prthp(CLK_TCK); 744} 745 746void 747masterup(net) 748 struct netinfo *net; 749{ 750 xmit(TSP_MASTERUP, 0, &net->dest_addr); 751 752 /* 753 * Do not tell new slaves our time for a while. This ensures 754 * we do not tell them to start using our time, before we have 755 * found a good master. 756 */ 757 (void)gettimeofday(&net->slvwait, 0); 758} 759 760void 761newslave(msg) 762 struct tsp *msg; 763{ 764 struct hosttbl *htp; 765 struct tsp *answer, to; 766 struct timeval now, tmptv; 767 768 if (!fromnet || fromnet->status != MASTER) 769 return; 770 771 htp = addmach(msg->tsp_name, &from,fromnet); 772 htp->seq = msg->tsp_seq; 773 if (trace) 774 prthp(0); 775 776 /* 777 * If we are stable, send our time to the slave. 778 * Do not go crazy if the date has been changed. 779 */ 780 (void)gettimeofday(&now, 0); 781 if (now.tv_sec >= fromnet->slvwait.tv_sec+3 782 || now.tv_sec < fromnet->slvwait.tv_sec) { 783 to.tsp_type = TSP_SETTIME; 784 (void)strcpy(to.tsp_name, hostname); 785 (void)gettimeofday(&tmptv, 0); 786 to.tsp_time.tv_sec = tmptv.tv_sec; 787 to.tsp_time.tv_usec = tmptv.tv_usec; 788 answer = acksend(&to, &htp->addr, 789 htp->name, TSP_ACK, 790 0, htp->noanswer); 791 if (answer) { 792 htp->need_set = 0; 793 } else { 794 syslog(LOG_WARNING, 795 "no reply to initial SETTIME from %s", 796 htp->name); 797 htp->noanswer = LOSTHOST; 798 } 799 } 800} 801 802 803/* 804 * react to a TSP_QUIT: 805 */ 806void 807doquit(msg) 808 struct tsp *msg; 809{ 810 if (fromnet->status == MASTER) { 811 if (!good_host_name(msg->tsp_name)) { 812 if (fromnet->quit_count <= 0) { 813 syslog(LOG_NOTICE,"untrusted %s told us QUIT", 814 msg->tsp_name); 815 suppress(&from, msg->tsp_name, fromnet); 816 fromnet->quit_count = 1; 817 return; 818 } 819 syslog(LOG_NOTICE, "untrusted %s told us QUIT twice", 820 msg->tsp_name); 821 fromnet->quit_count = 2; 822 fromnet->status = NOMASTER; 823 } else { 824 fromnet->status = SLAVE; 825 } 826 rmnetmachs(fromnet); 827 longjmp(jmpenv, 2); /* give up and be a slave */ 828 829 } else { 830 if (!good_host_name(msg->tsp_name)) { 831 syslog(LOG_NOTICE, "untrusted %s told us QUIT", 832 msg->tsp_name); 833 fromnet->quit_count = 2; 834 } 835 } 836} 837 838void 839traceon() 840{ 841 if (!fd) { 842 fd = fopen(_PATH_TIMEDLOG, "w"); 843 if (!fd) { 844 trace = 0; 845 return; 846 } 847 fprintf(fd,"Tracing started at %s\n", date()); 848 } 849 trace = 1; 850 get_goodgroup(1); 851 setstatus(); 852 prthp(CLK_TCK); 853} 854 855 856void 857traceoff(msg) 858 char *msg; 859{ 860 get_goodgroup(1); 861 setstatus(); 862 prthp(CLK_TCK); 863 if (trace) { 864 fprintf(fd, msg, date()); 865 (void)fclose(fd); 866 fd = 0; 867 } 868#ifdef GPROF 869 moncontrol(0); 870 _mcleanup(); 871 moncontrol(1); 872#endif 873 trace = OFF; 874} 875