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