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