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