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