1 /*- 2 * Copyright (c) 1985, 1993 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)master.c 5.1 (Berkeley) 05/11/93"; 10 #endif /* not lint */ 11 12 #ifdef sgi 13 #ident "$Revision: 1.21 $" 14 #endif 15 16 #include "globals.h" 17 #include <sys/file.h> 18 #include <sys/types.h> 19 #include <sys/times.h> 20 #include <setjmp.h> 21 #ifdef sgi 22 #include <sys/schedctl.h> 23 #endif /* sgi */ 24 #include <utmp.h> 25 #include "pathnames.h" 26 27 extern int measure_delta; 28 extern jmp_buf jmpenv; 29 extern int Mflag; 30 extern int justquit; 31 32 static int dictate; 33 static int slvcount; /* slaves listening to our clock */ 34 35 static void mchgdate __P((struct tsp *)); 36 37 #ifdef sgi 38 extern void logwtmp __P((struct timeval *, struct timeval *)); 39 #else 40 extern void logwtmp __P((char *, char *, char *)); 41 #endif /* sgi */ 42 43 /* 44 * The main function of `master' is to periodically compute the differences 45 * (deltas) between its clock and the clocks of the slaves, to compute the 46 * network average delta, and to send to the slaves the differences between 47 * their individual deltas and the network delta. 48 * While waiting, it receives messages from the slaves (i.e. requests for 49 * master's name, remote requests to set the network time, ...), and 50 * takes the appropriate action. 51 */ 52 int 53 master() 54 { 55 struct hosttbl *htp; 56 long pollingtime; 57 #define POLLRATE 4 58 int polls; 59 struct timeval wait, ntime; 60 struct tsp *msg, *answer, to; 61 char newdate[32]; 62 struct sockaddr_in taddr; 63 char tname[MAXHOSTNAMELEN]; 64 struct netinfo *ntp; 65 int i; 66 67 syslog(LOG_NOTICE, "This machine is master"); 68 if (trace) 69 fprintf(fd, "This machine is master\n"); 70 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 71 if (ntp->status == MASTER) 72 masterup(ntp); 73 } 74 (void)gettimeofday(&ntime, 0); 75 pollingtime = ntime.tv_sec+3; 76 if (justquit) 77 polls = 0; 78 else 79 polls = POLLRATE-1; 80 81 /* Process all outstanding messages before spending the long time necessary 82 * to update all timers. 83 */ 84 loop: 85 (void)gettimeofday(&ntime, 0); 86 wait.tv_sec = pollingtime - ntime.tv_sec; 87 if (wait.tv_sec < 0) 88 wait.tv_sec = 0; 89 wait.tv_usec = 0; 90 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); 91 if (!msg) { 92 (void)gettimeofday(&ntime, 0); 93 if (ntime.tv_sec >= pollingtime) { 94 pollingtime = ntime.tv_sec + SAMPLEINTVL; 95 get_goodgroup(0); 96 97 /* If a bogus master told us to quit, we can have decided to ignore a 98 * network. Therefore, periodically try to take over everything. 99 */ 100 polls = (polls + 1) % POLLRATE; 101 if (0 == polls && nignorednets > 0) { 102 trace_msg("Looking for nets to re-master\n"); 103 for (ntp = nettab; ntp; ntp = ntp->next) { 104 if (ntp->status == IGNORE 105 || ntp->status == NOMASTER) { 106 lookformaster(ntp); 107 if (ntp->status == MASTER) { 108 masterup(ntp); 109 polls = POLLRATE-1; 110 } 111 } 112 if (ntp->status == MASTER 113 && --ntp->quit_count < 0) 114 ntp->quit_count = 0; 115 } 116 if (polls != 0) 117 setstatus(); 118 } 119 120 synch(0L); 121 122 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 123 to.tsp_type = TSP_LOOP; 124 to.tsp_vers = TSPVERSION; 125 to.tsp_seq = sequence++; 126 to.tsp_hopcnt = MAX_HOPCNT; 127 (void)strcpy(to.tsp_name, hostname); 128 bytenetorder(&to); 129 if (sendto(sock, (char *)&to, 130 sizeof(struct tsp), 0, 131 (struct sockaddr*)&ntp->dest_addr, 132 sizeof(ntp->dest_addr)) < 0) { 133 trace_sendto_err(ntp->dest_addr.sin_addr); 134 } 135 } 136 } 137 138 139 } else { 140 switch (msg->tsp_type) { 141 142 case TSP_MASTERREQ: 143 break; 144 145 case TSP_SLAVEUP: 146 newslave(msg); 147 break; 148 149 case TSP_SETDATE: 150 /* 151 * XXX check to see it is from ourself 152 */ 153 #ifdef sgi 154 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); 155 #else 156 (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); 157 #endif /* sgi */ 158 if (!good_host_name(msg->tsp_name)) { 159 syslog(LOG_NOTICE, 160 "attempted date change by %s to %s", 161 msg->tsp_name, newdate); 162 spreadtime(); 163 break; 164 } 165 166 mchgdate(msg); 167 (void)gettimeofday(&ntime, 0); 168 pollingtime = ntime.tv_sec + SAMPLEINTVL; 169 break; 170 171 case TSP_SETDATEREQ: 172 if (!fromnet || fromnet->status != MASTER) 173 break; 174 #ifdef sgi 175 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); 176 #else 177 (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); 178 #endif /* sgi */ 179 htp = findhost(msg->tsp_name); 180 if (htp == 0) { 181 syslog(LOG_ERR, 182 "attempted SET DATEREQ by uncontrolled %s to %s", 183 msg->tsp_name, newdate); 184 break; 185 } 186 if (htp->seq == msg->tsp_seq) 187 break; 188 htp->seq = msg->tsp_seq; 189 if (!htp->good) { 190 syslog(LOG_NOTICE, 191 "attempted SET DATEREQ by untrusted %s to %s", 192 msg->tsp_name, newdate); 193 spreadtime(); 194 break; 195 } 196 197 mchgdate(msg); 198 (void)gettimeofday(&ntime, 0); 199 pollingtime = ntime.tv_sec + SAMPLEINTVL; 200 break; 201 202 case TSP_MSITE: 203 xmit(TSP_ACK, msg->tsp_seq, &from); 204 break; 205 206 case TSP_MSITEREQ: 207 break; 208 209 case TSP_TRACEON: 210 traceon(); 211 break; 212 213 case TSP_TRACEOFF: 214 traceoff("Tracing ended at %s\n"); 215 break; 216 217 case TSP_ELECTION: 218 if (!fromnet) 219 break; 220 if (fromnet->status == MASTER) { 221 pollingtime = 0; 222 (void)addmach(msg->tsp_name, &from,fromnet); 223 } 224 taddr = from; 225 (void)strcpy(tname, msg->tsp_name); 226 to.tsp_type = TSP_QUIT; 227 (void)strcpy(to.tsp_name, hostname); 228 answer = acksend(&to, &taddr, tname, 229 TSP_ACK, 0, 1); 230 if (answer == NULL) { 231 syslog(LOG_ERR, "election error by %s", 232 tname); 233 } 234 break; 235 236 case TSP_CONFLICT: 237 /* 238 * After a network partition, there can be 239 * more than one master: the first slave to 240 * come up will notify here the situation. 241 */ 242 if (!fromnet || fromnet->status != MASTER) 243 break; 244 (void)strcpy(to.tsp_name, hostname); 245 246 /* The other master often gets into the same state, 247 * with boring results if we stay at it forever. 248 */ 249 ntp = fromnet; /* (acksend() can leave fromnet=0 */ 250 for (i = 0; i < 3; i++) { 251 to.tsp_type = TSP_RESOLVE; 252 (void)strcpy(to.tsp_name, hostname); 253 answer = acksend(&to, &ntp->dest_addr, 254 ANYADDR, TSP_MASTERACK, 255 ntp, 0); 256 if (!answer) 257 break; 258 htp = addmach(answer->tsp_name,&from,ntp); 259 to.tsp_type = TSP_QUIT; 260 msg = acksend(&to, &htp->addr, htp->name, 261 TSP_ACK, 0, htp->noanswer); 262 if (msg == NULL) { 263 syslog(LOG_ERR, 264 "no response from %s to CONFLICT-QUIT", 265 htp->name); 266 } 267 } 268 masterup(ntp); 269 pollingtime = 0; 270 break; 271 272 case TSP_RESOLVE: 273 if (!fromnet || fromnet->status != MASTER) 274 break; 275 /* 276 * do not want to call synch() while waiting 277 * to be killed! 278 */ 279 (void)gettimeofday(&ntime, (struct timezone *)0); 280 pollingtime = ntime.tv_sec + SAMPLEINTVL; 281 break; 282 283 case TSP_QUIT: 284 doquit(msg); /* become a slave */ 285 break; 286 287 case TSP_LOOP: 288 if (!fromnet || fromnet->status != MASTER 289 || !strcmp(msg->tsp_name, hostname)) 290 break; 291 /* 292 * We should not have received this from a net 293 * we are master on. There must be two masters. 294 */ 295 htp = addmach(msg->tsp_name, &from,fromnet); 296 to.tsp_type = TSP_QUIT; 297 (void)strcpy(to.tsp_name, hostname); 298 answer = acksend(&to, &htp->addr, htp->name, 299 TSP_ACK, 0, 1); 300 if (!answer) { 301 syslog(LOG_WARNING, 302 "loop breakage: no reply from %s=%s to QUIT", 303 htp->name, inet_ntoa(htp->addr.sin_addr)); 304 (void)remmach(htp); 305 } 306 307 case TSP_TEST: 308 if (trace) { 309 fprintf(fd, 310 "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n", 311 nnets, nmasternets, nslavenets, nignorednets); 312 setstatus(); 313 } 314 pollingtime = 0; 315 polls = POLLRATE-1; 316 break; 317 318 default: 319 if (trace) { 320 fprintf(fd, "garbage message: "); 321 print(msg, &from); 322 } 323 break; 324 } 325 } 326 goto loop; 327 } 328 329 330 /* 331 * change the system date on the master 332 */ 333 static void 334 mchgdate(msg) 335 struct tsp *msg; 336 { 337 char tname[MAXHOSTNAMELEN]; 338 char olddate[32]; 339 struct timeval otime, ntime; 340 341 (void)strcpy(tname, msg->tsp_name); 342 343 xmit(TSP_DATEACK, msg->tsp_seq, &from); 344 345 (void)strcpy(olddate, date()); 346 347 /* adjust time for residence on the queue */ 348 (void)gettimeofday(&otime, 0); 349 adj_msg_time(msg,&otime); 350 351 timevalsub(&ntime, &msg->tsp_time, &otime); 352 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { 353 /* 354 * do not change the clock if we can adjust it 355 */ 356 dictate = 3; 357 synch(tvtomsround(ntime)); 358 } else { 359 #ifdef sgi 360 if (0 > settimeofday(&msg->tsp_time, 0)) { 361 syslog(LOG_ERR, "settimeofday(): %m"); 362 } 363 logwtmp(&otime, &msg->tsp_time); 364 #else 365 logwtmp("|", "date", ""); 366 (void)settimeofday(&msg->tsp_time, 0); 367 logwtmp("}", "date", ""); 368 #endif /* sgi */ 369 spreadtime(); 370 } 371 372 syslog(LOG_NOTICE, "date changed by %s from %s", 373 tname, olddate); 374 } 375 376 377 /* 378 * synchronize all of the slaves 379 */ 380 void 381 synch(mydelta) 382 long mydelta; 383 { 384 struct hosttbl *htp; 385 int measure_status; 386 struct timeval check, stop, wait; 387 #ifdef sgi 388 int pri; 389 #endif /* sgi */ 390 391 if (slvcount > 0) { 392 if (trace) 393 fprintf(fd, "measurements starting at %s\n", date()); 394 (void)gettimeofday(&check, 0); 395 #ifdef sgi 396 /* run fast to get good time */ 397 pri = schedctl(NDPRI,0,NDPHIMIN); 398 if (pri < 0) 399 syslog(LOG_ERR, "schedctl(): %m"); 400 #endif /* sgi */ 401 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 402 if (htp->noanswer != 0) { 403 measure_status = measure(500, 100, 404 htp->name, 405 &htp->addr,0); 406 } else { 407 measure_status = measure(3000, 100, 408 htp->name, 409 &htp->addr,0); 410 } 411 if (measure_status != GOOD) { 412 /* The slave did not respond. We have 413 * just wasted lots of time on it. 414 */ 415 htp->delta = HOSTDOWN; 416 if (++htp->noanswer >= LOSTHOST) { 417 if (trace) { 418 fprintf(fd, 419 "purging %s for not answering ICMP\n", 420 htp->name); 421 (void)fflush(fd); 422 } 423 htp = remmach(htp); 424 } 425 } else { 426 htp->delta = measure_delta; 427 } 428 (void)gettimeofday(&stop, 0); 429 timevalsub(&stop, &stop, &check); 430 if (stop.tv_sec >= 1) { 431 if (trace) 432 (void)fflush(fd); 433 /* 434 * ack messages periodically 435 */ 436 wait.tv_sec = 0; 437 wait.tv_usec = 0; 438 if (0 != readmsg(TSP_TRACEON,ANYADDR, 439 &wait,0)) 440 traceon(); 441 (void)gettimeofday(&check, 0); 442 } 443 } 444 #ifdef sgi 445 if (pri >= 0) 446 (void)schedctl(NDPRI,0,pri); 447 #endif /* sgi */ 448 if (trace) 449 fprintf(fd, "measurements finished at %s\n", date()); 450 } 451 if (!(status & SLAVE)) { 452 if (!dictate) { 453 mydelta = networkdelta(); 454 } else { 455 dictate--; 456 } 457 } 458 if (trace && (mydelta != 0 || (status & SLAVE))) 459 fprintf(fd,"local correction of %ld ms.\n", mydelta); 460 correct(mydelta); 461 } 462 463 /* 464 * sends the time to each slave after the master 465 * has received the command to set the network time 466 */ 467 void 468 spreadtime() 469 { 470 struct hosttbl *htp; 471 struct tsp to; 472 struct tsp *answer; 473 474 /* Do not listen to the consensus after forcing the time. This is because 475 * the consensus takes a while to reach the time we are dictating. 476 */ 477 dictate = 2; 478 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 479 to.tsp_type = TSP_SETTIME; 480 (void)strcpy(to.tsp_name, hostname); 481 (void)gettimeofday(&to.tsp_time, 0); 482 answer = acksend(&to, &htp->addr, htp->name, 483 TSP_ACK, 0, htp->noanswer); 484 if (answer == 0) { 485 /* We client does not respond, then we have 486 * just wasted lots of time on it. 487 */ 488 syslog(LOG_WARNING, 489 "no reply to SETTIME from %s", htp->name); 490 if (++htp->noanswer >= LOSTHOST) { 491 if (trace) { 492 fprintf(fd, 493 "purging %s for not answering", 494 htp->name); 495 (void)fflush(fd); 496 } 497 htp = remmach(htp); 498 } 499 } 500 } 501 } 502 503 void 504 prthp(delta) 505 clock_t delta; 506 { 507 static time_t next_time; 508 time_t this_time; 509 struct tms tm; 510 struct hosttbl *htp; 511 int length, l; 512 int i; 513 514 if (!fd) /* quit if tracing already off */ 515 return; 516 517 this_time = times(&tm); 518 if (this_time + delta < next_time) 519 return; 520 next_time = this_time + CLK_TCK; 521 522 fprintf(fd, "host table: %d entries at %s\n", slvcount, date()); 523 htp = self.l_fwd; 524 length = 1; 525 for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) { 526 l = strlen(htp->name) + 1; 527 if (length+l >= 80) { 528 fprintf(fd, "\n"); 529 length = 0; 530 } 531 length += l; 532 fprintf(fd, " %s", htp->name); 533 } 534 fprintf(fd, "\n"); 535 } 536 537 538 static struct hosttbl *newhost_hash; 539 static struct hosttbl *lasthfree = &hosttbl[0]; 540 541 542 struct hosttbl * /* answer or 0 */ 543 findhost(name) 544 char *name; 545 { 546 int i, j; 547 struct hosttbl *htp; 548 char *p; 549 550 j= 0; 551 for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++) 552 j = (j << 2) ^ *p; 553 newhost_hash = &hosttbl[j % NHOSTS]; 554 555 htp = newhost_hash; 556 if (htp->name[0] == '\0') 557 return(0); 558 do { 559 if (!strcmp(name, htp->name)) 560 return(htp); 561 htp = htp->h_fwd; 562 } while (htp != newhost_hash); 563 return(0); 564 } 565 566 /* 567 * add a host to the list of controlled machines if not already there 568 */ 569 struct hosttbl * 570 addmach(name, addr, ntp) 571 char *name; 572 struct sockaddr_in *addr; 573 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(htp) 660 struct hosttbl *htp; 661 { 662 struct hosttbl *lprv, *hnxt, *f, *b; 663 664 if (trace) 665 fprintf(fd, "remove %s\n", htp->name); 666 667 /* get out of the lists */ 668 htp->l_fwd->l_bak = lprv = htp->l_bak; 669 htp->l_bak->l_fwd = htp->l_fwd; 670 htp->h_fwd->h_bak = htp->h_bak; 671 htp->h_bak->h_fwd = hnxt = htp->h_fwd; 672 673 /* If we are in the home slot, pull up the chain */ 674 if (htp->head && hnxt != htp) { 675 if (lprv == hnxt) 676 lprv = htp; 677 678 /* Use scratch pointers in case the new head is pointing to 679 * itself. 680 */ 681 f = hnxt->h_fwd; 682 b = hnxt->h_bak; 683 f->h_bak = htp; 684 b->h_fwd = htp; 685 f = hnxt->l_fwd; 686 b = hnxt->l_bak; 687 f->l_bak = htp; 688 b->l_fwd = htp; 689 hnxt->head = 1; 690 bcopy(hnxt, htp, sizeof(*htp)); 691 lasthfree = hnxt; 692 } else { 693 lasthfree = htp; 694 } 695 696 lasthfree->name[0] = '\0'; 697 lasthfree->h_fwd = 0; 698 lasthfree->l_fwd = 0; 699 slvcount--; 700 701 return lprv; 702 } 703 704 705 /* 706 * Remove all the machines from the host table that exist on the given 707 * network. This is called when a master transitions to a slave on a 708 * given network. 709 */ 710 void 711 rmnetmachs(ntp) 712 struct netinfo *ntp; 713 { 714 struct hosttbl *htp; 715 716 if (trace) 717 prthp(CLK_TCK); 718 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 719 if (ntp == htp->ntp) 720 htp = remmach(htp); 721 } 722 if (trace) 723 prthp(CLK_TCK); 724 } 725 726 void 727 masterup(net) 728 struct netinfo *net; 729 { 730 xmit(TSP_MASTERUP, 0, &net->dest_addr); 731 732 /* 733 * Do not tell new slaves our time for a while. This ensures 734 * we do not tell them to start using our time, before we have 735 * found a good master. 736 */ 737 (void)gettimeofday(&net->slvwait, 0); 738 } 739 740 void 741 newslave(msg) 742 struct tsp *msg; 743 { 744 struct hosttbl *htp; 745 struct tsp *answer, to; 746 struct timeval now; 747 748 if (!fromnet || fromnet->status != MASTER) 749 return; 750 751 htp = addmach(msg->tsp_name, &from,fromnet); 752 htp->seq = msg->tsp_seq; 753 if (trace) 754 prthp(0); 755 756 /* 757 * If we are stable, send our time to the slave. 758 * Do not go crazy if the date has been changed. 759 */ 760 (void)gettimeofday(&now, 0); 761 if (now.tv_sec >= fromnet->slvwait.tv_sec+3 762 || now.tv_sec < fromnet->slvwait.tv_sec) { 763 to.tsp_type = TSP_SETTIME; 764 (void)strcpy(to.tsp_name, hostname); 765 (void)gettimeofday(&to.tsp_time, 0); 766 answer = acksend(&to, &htp->addr, 767 htp->name, TSP_ACK, 768 0, htp->noanswer); 769 if (answer) { 770 htp->need_set = 0; 771 } else { 772 syslog(LOG_WARNING, 773 "no reply to initial SETTIME from %s", 774 htp->name); 775 htp->noanswer = LOSTHOST; 776 } 777 } 778 } 779 780 781 /* 782 * react to a TSP_QUIT: 783 */ 784 void 785 doquit(msg) 786 struct tsp *msg; 787 { 788 if (fromnet->status == MASTER) { 789 if (!good_host_name(msg->tsp_name)) { 790 if (fromnet->quit_count <= 0) { 791 syslog(LOG_NOTICE,"untrusted %s told us QUIT", 792 msg->tsp_name); 793 suppress(&from, msg->tsp_name, fromnet); 794 fromnet->quit_count = 1; 795 return; 796 } 797 syslog(LOG_NOTICE, "untrusted %s told us QUIT twice", 798 msg->tsp_name); 799 fromnet->quit_count = 2; 800 fromnet->status = NOMASTER; 801 } else { 802 fromnet->status = SLAVE; 803 } 804 rmnetmachs(fromnet); 805 longjmp(jmpenv, 2); /* give up and be a slave */ 806 807 } else { 808 if (!good_host_name(msg->tsp_name)) { 809 syslog(LOG_NOTICE, "untrusted %s told us QUIT", 810 msg->tsp_name); 811 fromnet->quit_count = 2; 812 } 813 } 814 } 815 816 void 817 traceon() 818 { 819 if (!fd) { 820 fd = fopen(_PATH_TIMEDLOG, "w"); 821 if (!fd) { 822 trace = 0; 823 return; 824 } 825 fprintf(fd,"Tracing started at %s\n", date()); 826 } 827 trace = 1; 828 get_goodgroup(1); 829 setstatus(); 830 prthp(CLK_TCK); 831 } 832 833 834 void 835 traceoff(msg) 836 char *msg; 837 { 838 get_goodgroup(1); 839 setstatus(); 840 prthp(CLK_TCK); 841 if (trace) { 842 fprintf(fd, msg, date()); 843 (void)fclose(fd); 844 fd = 0; 845 } 846 #ifdef GPROF 847 moncontrol(0); 848 _mcleanup(); 849 moncontrol(1); 850 #endif 851 trace = OFF; 852 } 853 854 855 #ifdef sgi 856 void 857 logwtmp(otime, ntime) 858 struct timeval *otime, *ntime; 859 { 860 static struct utmp wtmp[2] = { 861 {"","",OTIME_MSG,0,OLD_TIME,0,0,0}, 862 {"","",NTIME_MSG,0,NEW_TIME,0,0,0} 863 }; 864 static char *wtmpfile = WTMP_FILE; 865 int f; 866 867 wtmp[0].ut_time = otime->tv_sec + (otime->tv_usec + 500000) / 1000000; 868 wtmp[1].ut_time = ntime->tv_sec + (ntime->tv_usec + 500000) / 1000000; 869 if (wtmp[0].ut_time == wtmp[1].ut_time) 870 return; 871 872 setutent(); 873 (void)pututline(&wtmp[0]); 874 (void)pututline(&wtmp[1]); 875 endutent(); 876 if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) { 877 (void) write(f, (char *)wtmp, sizeof(wtmp)); 878 (void) close(f); 879 } 880 } 881 #endif /* sgi */ 882