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