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
master(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
mchgdate(struct tsp * msg)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
synch(long mydelta)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
spreadtime(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
prthp(clock_t delta)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 */
findhost(char * name)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 *
addmach(char * name,struct sockaddr_in * addr,struct netinfo * ntp)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 *
remmach(struct hosttbl * htp)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
rmnetmachs(struct netinfo * ntp)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
masterup(struct netinfo * net)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
newslave(struct tsp * msg)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
doquit(struct tsp * msg)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
traceon(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
traceoff(const char * msg)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