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