Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[games.git] / usr.sbin / timed / timed / master.c
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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)master.c 8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.sbin/timed/timed/master.c,v 1.6 1999/08/28 01:20:17 peter Exp $
35  */
36
37 #include "globals.h"
38 #include <sys/file.h>
39 #include <sys/types.h>
40 #include <sys/times.h>
41 #include <setjmp.h>
42 #include <utmp.h>
43 #include "pathnames.h"
44
45 extern int measure_delta;
46 extern jmp_buf jmpenv;
47 extern int Mflag;
48 extern int justquit;
49
50 static int dictate;
51 static int slvcount;                    /* slaves listening to our clock */
52
53 static void mchgdate(struct tsp *);
54
55 /*
56  * The main function of `master' is to periodically compute the differences
57  * (deltas) between its clock and the clocks of the slaves, to compute the
58  * network average delta, and to send to the slaves the differences between
59  * their individual deltas and the network delta.
60  * While waiting, it receives messages from the slaves (i.e. requests for
61  * master's name, remote requests to set the network time, ...), and
62  * takes the appropriate action.
63  */
64 int
65 master(void)
66 {
67         struct hosttbl *htp;
68         long pollingtime;
69 #define POLLRATE 4
70         int polls;
71         struct timeval wait, ntime;
72         time_t tsp_time_sec;
73         struct tsp *msg, *answer, to;
74         char newdate[32];
75         struct sockaddr_in taddr;
76         char tname[MAXHOSTNAMELEN];
77         struct netinfo *ntp;
78         int i;
79
80         syslog(LOG_NOTICE, "This machine is master");
81         if (trace)
82                 fprintf(fd, "This machine is master\n");
83         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
84                 if (ntp->status == MASTER)
85                         masterup(ntp);
86         }
87         gettimeofday(&ntime, 0);
88         pollingtime = ntime.tv_sec+3;
89         if (justquit)
90                 polls = 0;
91         else
92                 polls = POLLRATE-1;
93
94 /* Process all outstanding messages before spending the long time necessary
95  *      to update all timers.
96  */
97 loop:
98         gettimeofday(&ntime, 0);
99         wait.tv_sec = pollingtime - ntime.tv_sec;
100         if (wait.tv_sec < 0)
101                 wait.tv_sec = 0;
102         wait.tv_usec = 0;
103         msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
104         if (!msg) {
105                 gettimeofday(&ntime, 0);
106                 if (ntime.tv_sec >= pollingtime) {
107                         pollingtime = ntime.tv_sec + SAMPLEINTVL;
108                         get_goodgroup(0);
109
110 /* If a bogus master told us to quit, we can have decided to ignore a
111  * network.  Therefore, periodically try to take over everything.
112  */
113                         polls = (polls + 1) % POLLRATE;
114                         if (0 == polls && nignorednets > 0) {
115                                 trace_msg("Looking for nets to re-master\n");
116                                 for (ntp = nettab; ntp; ntp = ntp->next) {
117                                         if (ntp->status == IGNORE
118                                             || ntp->status == NOMASTER) {
119                                                 lookformaster(ntp);
120                                                 if (ntp->status == MASTER) {
121                                                         masterup(ntp);
122                                                         polls = POLLRATE-1;
123                                                 }
124                                         }
125                                         if (ntp->status == MASTER
126                                             && --ntp->quit_count < 0)
127                                                 ntp->quit_count = 0;
128                                 }
129                                 if (polls != 0)
130                                         setstatus();
131                         }
132
133                         synch(0L);
134
135                         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
136                                 to.tsp_type = TSP_LOOP;
137                                 to.tsp_vers = TSPVERSION;
138                                 to.tsp_seq = sequence++;
139                                 to.tsp_hopcnt = MAX_HOPCNT;
140                                 strlcpy(to.tsp_name, hostname, 
141                                         sizeof(to.tsp_name));
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                         strlcpy(newdate, ctime(&tsp_time_sec), 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                         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                         tsp_time_sec = msg->tsp_time.tv_sec;
186                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
187                         htp = findhost(msg->tsp_name);
188                         if (htp == NULL) {
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                         gettimeofday(&ntime, 0);
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                                 addmach(msg->tsp_name, &from,fromnet);
231                         }
232                         taddr = from;
233                         strlcpy(tname, msg->tsp_name, sizeof(tname));
234                         to.tsp_type = TSP_QUIT;
235                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
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                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
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                                 strlcpy(to.tsp_name, hostname, 
261                                         sizeof(to.tsp_name));
262                                 answer = acksend(&to, &ntp->dest_addr,
263                                                  ANYADDR, TSP_MASTERACK,
264                                                  ntp, 0);
265                                 if (!answer)
266                                         break;
267                                 htp = addmach(answer->tsp_name,&from,ntp);
268                                 to.tsp_type = TSP_QUIT;
269                                 msg = acksend(&to, &htp->addr, htp->name,
270                                               TSP_ACK, 0, htp->noanswer);
271                                 if (msg == NULL) {
272                                         syslog(LOG_ERR,
273                                     "no response from %s to CONFLICT-QUIT",
274                                                htp->name);
275                                 }
276                         }
277                         masterup(ntp);
278                         pollingtime = 0;
279                         break;
280
281                 case TSP_RESOLVE:
282                         if (!fromnet || fromnet->status != MASTER)
283                                 break;
284                         /*
285                          * do not want to call synch() while waiting
286                          * to be killed!
287                          */
288                         gettimeofday(&ntime, NULL);
289                         pollingtime = ntime.tv_sec + SAMPLEINTVL;
290                         break;
291
292                 case TSP_QUIT:
293                         doquit(msg);            /* become a slave */
294                         break;
295
296                 case TSP_LOOP:
297                         if (!fromnet || fromnet->status != MASTER
298                             || !strcmp(msg->tsp_name, hostname))
299                                 break;
300                         /*
301                          * We should not have received this from a net
302                          * we are master on.  There must be two masters.
303                          */
304                         htp = addmach(msg->tsp_name, &from,fromnet);
305                         to.tsp_type = TSP_QUIT;
306                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
307                         answer = acksend(&to, &htp->addr, htp->name,
308                                          TSP_ACK, 0, 1);
309                         if (!answer) {
310                                 syslog(LOG_WARNING,
311                                 "loop breakage: no reply from %s=%s to QUIT",
312                                     htp->name, inet_ntoa(htp->addr.sin_addr));
313                                 remmach(htp);
314                         }
315
316                 case TSP_TEST:
317                         if (trace) {
318                                 fprintf(fd,
319                 "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
320                 nnets, nmasternets, nslavenets, nignorednets);
321                                 setstatus();
322                         }
323                         pollingtime = 0;
324                         polls = POLLRATE-1;
325                         break;
326
327                 default:
328                         if (trace) {
329                                 fprintf(fd, "garbage message: ");
330                                 print(msg, &from);
331                         }
332                         break;
333                 }
334         }
335         goto loop;
336 }
337
338
339 /*
340  * change the system date on the master
341  */
342 static void
343 mchgdate(struct tsp *msg)
344 {
345         char tname[MAXHOSTNAMELEN];
346         char olddate[32];
347         struct timeval otime, ntime;
348
349         strlcpy(tname, msg->tsp_name, sizeof(tname));
350
351         xmit(TSP_DATEACK, msg->tsp_seq, &from);
352
353         strlcpy(olddate, date(), sizeof(olddate));
354
355         /* adjust time for residence on the queue */
356         gettimeofday(&otime, 0);
357         adj_msg_time(msg,&otime);
358
359         timevalsub(&ntime, &msg->tsp_time, &otime);
360         if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
361                 /*
362                  * do not change the clock if we can adjust it
363                  */
364                 dictate = 3;
365                 synch(tvtomsround(ntime));
366         } else {
367                 logwtmp("|", "date", "");
368                 settimeofday(&msg->tsp_time, 0);
369                 logwtmp("{", "date", "");
370                 spreadtime();
371         }
372
373         syslog(LOG_NOTICE, "date changed by %s from %s",
374                tname, olddate);
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                 gettimeofday(&check, 0);
392                 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
393                         if (htp->noanswer != 0) {
394                                 measure_status = measure(500, 100,
395                                                          htp->name,
396                                                          &htp->addr,0);
397                         } else {
398                                 measure_status = measure(3000, 100,
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                                                 fflush(fd);
413                                         }
414                                         htp = remmach(htp);
415                                 }
416                         } else {
417                                 htp->delta = measure_delta;
418                         }
419                         gettimeofday(&stop, 0);
420                         timevalsub(&stop, &stop, &check);
421                         if (stop.tv_sec >= 1) {
422                                 if (trace)
423                                         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                                 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
461 /* Do not listen to the consensus after forcing the time.  This is because
462  *      the consensus takes a while to reach the time we are dictating.
463  */
464         dictate = 2;
465         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
466                 to.tsp_type = TSP_SETTIME;
467                 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
468                 gettimeofday(&to.tsp_time, 0);
469                 answer = acksend(&to, &htp->addr, htp->name,
470                                  TSP_ACK, 0, htp->noanswer);
471                 if (answer == NULL) {
472                         /* We client does not respond, then we have
473                          * just wasted lots of time on it.
474                          */
475                         syslog(LOG_WARNING,
476                                "no reply to SETTIME from %s", htp->name);
477                         if (++htp->noanswer >= LOSTHOST) {
478                                 if (trace) {
479                                         fprintf(fd,
480                                              "purging %s for not answering",
481                                                 htp->name);
482                                         fflush(fd);
483                                 }
484                                 htp = remmach(htp);
485                         }
486                 }
487         }
488 }
489
490 void
491 prthp(clock_t delta)
492 {
493         static time_t next_time;
494         time_t this_time;
495         struct tms tm;
496         struct hosttbl *htp;
497         int length, l;
498         int i;
499
500         if (!fd)                        /* quit if tracing already off */
501                 return;
502
503         this_time = times(&tm);
504         if (this_time + (time_t)delta < next_time)
505                 return;
506         next_time = this_time + CLK_TCK;
507
508         fprintf(fd, "host table: %d entries at %s\n", slvcount, date());
509         htp = self.l_fwd;
510         length = 1;
511         for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) {
512                 l = strlen(htp->name) + 1;
513                 if (length+l >= 80) {
514                         fprintf(fd, "\n");
515                         length = 0;
516                 }
517                 length += l;
518                 fprintf(fd, " %s", htp->name);
519         }
520         fprintf(fd, "\n");
521 }
522
523
524 static struct hosttbl *newhost_hash;
525 static struct hosttbl *lasthfree = &hosttbl[0];
526
527
528 struct hosttbl *                        /* answer or 0 */
529 findhost(char *name)
530 {
531         int i, j;
532         struct hosttbl *htp;
533         char *p;
534
535         j= 0;
536         for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++)
537                 j = (j << 2) ^ *p;
538         newhost_hash = &hosttbl[j % NHOSTS];
539
540         htp = newhost_hash;
541         if (htp->name[0] == '\0')
542                 return(0);
543         do {
544                 if (!strcmp(name, htp->name))
545                         return(htp);
546                 htp = htp->h_fwd;
547         } while (htp != newhost_hash);
548         return(0);
549 }
550
551 /*
552  * add a host to the list of controlled machines if not already there
553  */
554 struct hosttbl *
555 addmach(char *name, struct sockaddr_in *addr, struct netinfo *ntp)
556 {
557         struct hosttbl *ret, *p, *b, *f;
558
559         ret = findhost(name);
560         if (ret == NULL) {
561                 if (slvcount >= NHOSTS) {
562                         if (trace) {
563                                 fprintf(fd, "no more slots in host table\n");
564                                 prthp(CLK_TCK);
565                         }
566                         syslog(LOG_ERR, "no more slots in host table");
567                         Mflag = 0;
568                         longjmp(jmpenv, 2); /* give up and be a slave */
569                 }
570
571                 /* if our home hash slot is occupied, find a free entry
572                  * in the hash table
573                  */
574                 if (newhost_hash->name[0] != '\0') {
575                         do {
576                                 ret = lasthfree;
577                                 if (++lasthfree > &hosttbl[NHOSTS])
578                                         lasthfree = &hosttbl[1];
579                         } while (ret->name[0] != '\0');
580
581                         if (!newhost_hash->head) {
582                                 /* Move an interloper using our home.  Use
583                                  * scratch pointers in case the new head is
584                                  * pointing to itself.
585                                  */
586                                 f = newhost_hash->h_fwd;
587                                 b = newhost_hash->h_bak;
588                                 f->h_bak = ret;
589                                 b->h_fwd = ret;
590                                 f = newhost_hash->l_fwd;
591                                 b = newhost_hash->l_bak;
592                                 f->l_bak = ret;
593                                 b->l_fwd = ret;
594                                 bcopy(newhost_hash,ret,sizeof(*ret));
595                                 ret = newhost_hash;
596                                 ret->head = 1;
597                                 ret->h_fwd = ret;
598                                 ret->h_bak = ret;
599                         } else {
600                                 /* link to an existing chain in our home
601                                  */
602                                 ret->head = 0;
603                                 p = newhost_hash->h_bak;
604                                 ret->h_fwd = newhost_hash;
605                                 ret->h_bak = p;
606                                 p->h_fwd = ret;
607                                 newhost_hash->h_bak = ret;
608                         }
609                 } else {
610                         ret = newhost_hash;
611                         ret->head = 1;
612                         ret->h_fwd = ret;
613                         ret->h_bak = ret;
614                 }
615                 ret->addr = *addr;
616                 ret->ntp = ntp;
617                 strlcpy(ret->name, name, sizeof(ret->name));
618                 ret->good = good_host_name(name);
619                 ret->l_fwd = &self;
620                 ret->l_bak = self.l_bak;
621                 self.l_bak->l_fwd = ret;
622                 self.l_bak = ret;
623                 slvcount++;
624
625                 ret->noanswer = 0;
626                 ret->need_set = 1;
627
628         } else {
629                 ret->noanswer = (ret->noanswer != 0);
630         }
631
632         /* need to clear sequence number anyhow */
633         ret->seq = 0;
634         return(ret);
635 }
636
637 /*
638  * remove the machine with the given index in the host table.
639  */
640 struct hosttbl *
641 remmach(struct hosttbl *htp)
642 {
643         struct hosttbl *lprv, *hnxt, *f, *b;
644
645         if (trace)
646                 fprintf(fd, "remove %s\n", htp->name);
647
648         /* get out of the lists */
649         htp->l_fwd->l_bak = lprv = htp->l_bak;
650         htp->l_bak->l_fwd = htp->l_fwd;
651         htp->h_fwd->h_bak = htp->h_bak;
652         htp->h_bak->h_fwd = hnxt = htp->h_fwd;
653
654         /* If we are in the home slot, pull up the chain */
655         if (htp->head && hnxt != htp) {
656                 if (lprv == hnxt)
657                         lprv = htp;
658
659                 /* Use scratch pointers in case the new head is pointing to
660                  * itself.
661                  */
662                 f = hnxt->h_fwd;
663                 b = hnxt->h_bak;
664                 f->h_bak = htp;
665                 b->h_fwd = htp;
666                 f = hnxt->l_fwd;
667                 b = hnxt->l_bak;
668                 f->l_bak = htp;
669                 b->l_fwd = htp;
670                 hnxt->head = 1;
671                 bcopy(hnxt, htp, sizeof(*htp));
672                 lasthfree = hnxt;
673         } else {
674                 lasthfree = htp;
675         }
676
677         lasthfree->name[0] = '\0';
678         lasthfree->h_fwd = 0;
679         lasthfree->l_fwd = 0;
680         slvcount--;
681
682         return lprv;
683 }
684
685
686 /*
687  * Remove all the machines from the host table that exist on the given
688  * network.  This is called when a master transitions to a slave on a
689  * given network.
690  */
691 void
692 rmnetmachs(struct netinfo *ntp)
693 {
694         struct hosttbl *htp;
695
696         if (trace)
697                 prthp(CLK_TCK);
698         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
699                 if (ntp == htp->ntp)
700                         htp = remmach(htp);
701         }
702         if (trace)
703                 prthp(CLK_TCK);
704 }
705
706 void
707 masterup(struct netinfo *net)
708 {
709
710         xmit(TSP_MASTERUP, 0, &net->dest_addr);
711
712         /*
713          * Do not tell new slaves our time for a while.  This ensures
714          * we do not tell them to start using our time, before we have
715          * found a good master.
716          */
717         gettimeofday(&net->slvwait, 0);
718 }
719
720 void
721 newslave(struct tsp *msg)
722 {
723         struct hosttbl *htp;
724         struct tsp *answer, to;
725         struct timeval now;
726
727         if (!fromnet || fromnet->status != MASTER)
728                 return;
729
730         htp = addmach(msg->tsp_name, &from,fromnet);
731         htp->seq = msg->tsp_seq;
732         if (trace)
733                 prthp(0);
734
735         /*
736          * If we are stable, send our time to the slave.
737          * Do not go crazy if the date has been changed.
738          */
739         gettimeofday(&now, 0);
740         if (now.tv_sec >= fromnet->slvwait.tv_sec+3
741             || now.tv_sec < fromnet->slvwait.tv_sec) {
742                 to.tsp_type = TSP_SETTIME;
743                 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
744                 gettimeofday(&to.tsp_time, 0);
745                 answer = acksend(&to, &htp->addr,
746                                  htp->name, TSP_ACK,
747                                  0, htp->noanswer);
748                 if (answer) {
749                         htp->need_set = 0;
750                 } else {
751                         syslog(LOG_WARNING,
752                                "no reply to initial SETTIME from %s",
753                                htp->name);
754                         htp->noanswer = LOSTHOST;
755                 }
756         }
757 }
758
759
760 /*
761  * react to a TSP_QUIT:
762  */
763 void
764 doquit(struct tsp *msg)
765 {
766
767         if (fromnet->status == MASTER) {
768                 if (!good_host_name(msg->tsp_name)) {
769                         if (fromnet->quit_count <= 0) {
770                                 syslog(LOG_NOTICE,"untrusted %s told us QUIT",
771                                        msg->tsp_name);
772                                 suppress(&from, msg->tsp_name, fromnet);
773                                 fromnet->quit_count = 1;
774                                 return;
775                         }
776                         syslog(LOG_NOTICE, "untrusted %s told us QUIT twice",
777                                msg->tsp_name);
778                         fromnet->quit_count = 2;
779                         fromnet->status = NOMASTER;
780                 } else {
781                         fromnet->status = SLAVE;
782                 }
783                 rmnetmachs(fromnet);
784                 longjmp(jmpenv, 2);             /* give up and be a slave */
785
786         } else {
787                 if (!good_host_name(msg->tsp_name)) {
788                         syslog(LOG_NOTICE, "untrusted %s told us QUIT",
789                                msg->tsp_name);
790                         fromnet->quit_count = 2;
791                 }
792         }
793 }
794
795 void
796 traceon(void)
797 {
798
799         if (!fd) {
800                 fd = fopen(_PATH_TIMEDLOG, "w");
801                 if (!fd) {
802                         trace = 0;
803                         return;
804                 }
805                 fprintf(fd,"Tracing started at %s\n", date());
806         }
807         trace = 1;
808         get_goodgroup(1);
809         setstatus();
810         prthp(CLK_TCK);
811 }
812
813
814 void
815 traceoff(char *msg)
816 {
817
818         get_goodgroup(1);
819         setstatus();
820         prthp(CLK_TCK);
821         if (trace) {
822                 fprintf(fd, msg, date());
823                 fclose(fd);
824                 fd = 0;
825         }
826 #ifdef GPROF
827         moncontrol(0);
828         _mcleanup();
829         moncontrol(1);
830 #endif
831         trace = OFF;
832 }
833