Make timed WARNS 2 compatible.
[dragonfly.git] / usr.sbin / timed / timed / slave.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  * @(#)slave.c  8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.sbin/timed/timed/slave.c,v 1.7 1999/08/28 01:20:18 peter Exp $
35  * $DragonFly: src/usr.sbin/timed/timed/slave.c,v 1.7 2004/09/05 02:09:24 dillon Exp $
36  */
37
38 #include "globals.h"
39 #include <setjmp.h>
40 #include "pathnames.h"
41
42 extern jmp_buf jmpenv;
43 extern int Mflag;
44 extern int justquit;
45
46 extern u_short sequence;
47
48 static char master_name[MAXHOSTNAMELEN];
49 static struct netinfo *old_slavenet;
50 static int old_status;
51
52 static void schgdate(struct tsp *, char *);
53 static void setmaster(struct tsp *);
54 static void answerdelay(void);
55
56 #ifdef sgi
57 extern void logwtmp(struct timeval *, struct timeval *);
58 #else
59 extern void logwtmp(char *, char *, char *);
60 #endif /* sgi */
61
62 int
63 slave(void)
64 {
65         int tries;
66         long electiontime, refusetime, looktime, looptime, adjusttime;
67         u_short seq;
68         long fastelection;
69 #define FASTTOUT 3
70         struct in_addr cadr;
71         struct timeval otime;
72         struct sockaddr_in taddr;
73         char tname[MAXHOSTNAMELEN];
74         struct tsp *msg, to;
75         struct timeval ntime, wait;
76         time_t tsp_time_sec;
77         struct tsp *answer;
78         char olddate[32];
79         char newdate[32];
80         struct netinfo *ntp;
81         struct hosttbl *htp;
82
83
84         old_slavenet = 0;
85         seq = 0;
86         refusetime = 0;
87         adjusttime = 0;
88
89         (void)gettimeofday(&ntime, 0);
90         electiontime = ntime.tv_sec + delay2;
91         fastelection = ntime.tv_sec + FASTTOUT;
92         if (justquit)
93                 looktime = electiontime;
94         else
95                 looktime = fastelection;
96         looptime = fastelection;
97
98         if (slavenet)
99                 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
100         if (status & MASTER) {
101                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
102                         if (ntp->status == MASTER)
103                                 masterup(ntp);
104                 }
105         }
106
107 loop:
108         get_goodgroup(0);
109         (void)gettimeofday(&ntime, (struct timezone *)0);
110         if (ntime.tv_sec > electiontime) {
111                 if (trace)
112                         fprintf(fd, "election timer expired\n");
113                 longjmp(jmpenv, 1);
114         }
115
116         if (ntime.tv_sec >= looktime) {
117                 if (trace)
118                         fprintf(fd, "Looking for nets to master\n");
119
120                 if (Mflag && nignorednets > 0) {
121                         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
122                                 if (ntp->status == IGNORE
123                                     || ntp->status == NOMASTER) {
124                                         lookformaster(ntp);
125                                         if (ntp->status == MASTER) {
126                                                 masterup(ntp);
127                                         } else if (ntp->status == MASTER) {
128                                                 ntp->status = NOMASTER;
129                                         }
130                                 }
131                                 if (ntp->status == MASTER
132                                     && --ntp->quit_count < 0)
133                                         ntp->quit_count = 0;
134                         }
135                         makeslave(slavenet);    /* prune extras */
136                         setstatus();
137                 }
138                 (void)gettimeofday(&ntime, 0);
139                 looktime = ntime.tv_sec + delay2;
140         }
141         if (ntime.tv_sec >= looptime) {
142                 if (trace)
143                         fprintf(fd, "Looking for loops\n");
144                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
145                     if (ntp->status == MASTER) {
146                         to.tsp_type = TSP_LOOP;
147                         to.tsp_vers = TSPVERSION;
148                         to.tsp_seq = sequence++;
149                         to.tsp_hopcnt = MAX_HOPCNT;
150                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
151                         bytenetorder(&to);
152                         if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
153                                    (struct sockaddr*)&ntp->dest_addr,
154                                    sizeof(ntp->dest_addr)) < 0) {
155                                 trace_sendto_err(ntp->dest_addr.sin_addr);
156                         }
157                     }
158                 }
159                 (void)gettimeofday(&ntime, 0);
160                 looptime = ntime.tv_sec + delay2;
161         }
162
163         wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
164         if (wait.tv_sec < 0)
165                 wait.tv_sec = 0;
166         wait.tv_sec += FASTTOUT;
167         wait.tv_usec = 0;
168         msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
169
170         if (msg != NULL) {
171                 /*
172                  * filter stuff not for us
173                  */
174                 switch (msg->tsp_type) {
175                 case TSP_SETDATE:
176                 case TSP_TRACEOFF:
177                 case TSP_TRACEON:
178                         /*
179                          * XXX check to see they are from ourself
180                          */
181                         break;
182
183                 case TSP_TEST:
184                 case TSP_MSITE:
185                         break;
186
187                 case TSP_MASTERUP:
188                         if (!fromnet) {
189                                 if (trace) {
190                                         fprintf(fd, "slave ignored: ");
191                                         print(msg, &from);
192                                 }
193                                 goto loop;
194                         }
195                         break;
196
197                 default:
198                         if (!fromnet
199                             || fromnet->status == IGNORE
200                             || fromnet->status == NOMASTER) {
201                                 if (trace) {
202                                         fprintf(fd, "slave ignored: ");
203                                         print(msg, &from);
204                                 }
205                                 goto loop;
206                         }
207                         break;
208                 }
209
210
211                 /*
212                  * now process the message
213                  */
214                 switch (msg->tsp_type) {
215
216                 case TSP_ADJTIME:
217                         if (fromnet != slavenet)
218                                 break;
219                         if (!good_host_name(msg->tsp_name)) {
220                                 syslog(LOG_NOTICE,
221                                    "attempted time adjustment by %s",
222                                        msg->tsp_name);
223                                 suppress(&from, msg->tsp_name, fromnet);
224                                 break;
225                         }
226                         /*
227                          * Speed up loop detection in case we have a loop.
228                          * Otherwise the clocks can race until the loop
229                          * is found.
230                          */
231                         (void)gettimeofday(&otime, 0);
232                         if (adjusttime < otime.tv_sec)
233                                 looptime -= (looptime-otime.tv_sec)/2 + 1;
234
235                         setmaster(msg);
236                         if (seq != msg->tsp_seq) {
237                                 seq = msg->tsp_seq;
238                                 synch(tvtomsround(msg->tsp_time));
239                         }
240                         (void)gettimeofday(&ntime, 0);
241                         electiontime = ntime.tv_sec + delay2;
242                         fastelection = ntime.tv_sec + FASTTOUT;
243                         adjusttime = ntime.tv_sec + SAMPLEINTVL*2;
244                         break;
245
246                 case TSP_SETTIME:
247                         if (fromnet != slavenet)
248                                 break;
249                         if (seq == msg->tsp_seq)
250                                 break;
251                         seq = msg->tsp_seq;
252
253                         /* adjust time for residence on the queue */
254                         (void)gettimeofday(&otime, 0);
255                         adj_msg_time(msg,&otime);
256 #ifdef sgi
257                         (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
258                         (void)cftime(olddate, "%D %T", &otime.tv_sec);
259 #else
260                         /*
261                          * the following line is necessary due to syslog
262                          * calling ctime() which clobbers the static buffer
263                          */
264                         strlcpy(olddate, date(), sizeof(olddate));
265                         tsp_time_sec = msg->tsp_time.tv_sec;
266                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
267 #endif /* sgi */
268
269                         if (!good_host_name(msg->tsp_name)) {
270                                 syslog(LOG_NOTICE,
271                             "attempted time setting by untrusted %s to %s",
272                                        msg->tsp_name, newdate);
273                                 suppress(&from, msg->tsp_name, fromnet);
274                                 break;
275                         }
276
277                         setmaster(msg);
278                         timevalsub(&ntime, &msg->tsp_time, &otime);
279                         if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
280                                 /*
281                                  * do not change the clock if we can adjust it
282                                  */
283                                 synch(tvtomsround(ntime));
284                         } else {
285 #ifdef sgi
286                                 if (0 > settimeofday(&msg->tsp_time, 0)) {
287                                         syslog(LOG_ERR,"settimeofdate(): %m");
288                                         break;
289                                 }
290                                 logwtmp(&otime, &msg->tsp_time);
291 #else
292                                 logwtmp("|", "date", "");
293                                 (void)settimeofday(&msg->tsp_time, 0);
294                                 logwtmp("{", "date", "");
295 #endif /* sgi */
296                                 syslog(LOG_NOTICE,
297                                        "date changed by %s from %s",
298                                         msg->tsp_name, olddate);
299                                 if (status & MASTER)
300                                         spreadtime();
301                         }
302                         (void)gettimeofday(&ntime, 0);
303                         electiontime = ntime.tv_sec + delay2;
304                         fastelection = ntime.tv_sec + FASTTOUT;
305
306 /* This patches a bad protocol bug.  Imagine a system with several networks,
307  * where there are a pair of redundant gateways between a pair of networks,
308  * each running timed.  Assume that we start with a third machine mastering
309  * one of the networks, and one of the gateways mastering the other.
310  * Imagine that the third machine goes away and the non-master gateway
311  * decides to replace it.  If things are timed just 'right,' we will have
312  * each gateway mastering one network for a little while.  If a SETTIME
313  * message gets into the network at that time, perhaps from the newly
314  * masterful gateway as it was taking control, the SETTIME will loop
315  * forever.  Each time a gateway receives it on its slave side, it will
316  * call spreadtime to forward it on its mastered network.  We are now in
317  * a permanent loop, since the SETTIME msgs will keep any clock
318  * in the network from advancing.  Normally, the 'LOOP' stuff will detect
319  * and correct the situation.  However, with the clocks stopped, the
320  * 'looptime' timer cannot expire.  While they are in this state, the
321  * masters will try to saturate the network with SETTIME packets.
322  */
323                         looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
324                         break;
325
326                 case TSP_MASTERUP:
327                         if (slavenet && fromnet != slavenet)
328                                 break;
329                         if (!good_host_name(msg->tsp_name)) {
330                                 suppress(&from, msg->tsp_name, fromnet);
331                                 if (electiontime > fastelection)
332                                         electiontime = fastelection;
333                                 break;
334                         }
335                         makeslave(fromnet);
336                         setmaster(msg);
337                         setstatus();
338                         answerdelay();
339                         xmit(TSP_SLAVEUP, 0, &from);
340                         (void)gettimeofday(&ntime, 0);
341                         electiontime = ntime.tv_sec + delay2;
342                         fastelection = ntime.tv_sec + FASTTOUT;
343                         refusetime = 0;
344                         break;
345
346                 case TSP_MASTERREQ:
347                         if (fromnet->status != SLAVE)
348                                 break;
349                         (void)gettimeofday(&ntime, 0);
350                         electiontime = ntime.tv_sec + delay2;
351                         break;
352
353                 case TSP_SETDATE:
354 #ifdef sgi
355                         (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
356 #else
357                         tsp_time_sec = msg->tsp_time.tv_sec;
358                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
359 #endif /* sgi */
360                         schgdate(msg, newdate);
361                         break;
362
363                 case TSP_SETDATEREQ:
364                         if (fromnet->status != MASTER)
365                                 break;
366 #ifdef sgi
367                         (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
368 #else
369                         tsp_time_sec = msg->tsp_time.tv_sec;
370                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
371 #endif /* sgi */
372                         htp = findhost(msg->tsp_name);
373                         if (0 == htp) {
374                                 syslog(LOG_WARNING,
375                                        "DATEREQ from uncontrolled machine");
376                                 break;
377                         }
378                         if (!htp->good) {
379                                 syslog(LOG_WARNING,
380                                 "attempted date change by untrusted %s to %s",
381                                        htp->name, newdate);
382                                 spreadtime();
383                                 break;
384                         }
385                         schgdate(msg, newdate);
386                         break;
387
388                 case TSP_TRACEON:
389                         traceon();
390                         break;
391
392                 case TSP_TRACEOFF:
393                         traceoff("Tracing ended at %s\n");
394                         break;
395
396                 case TSP_SLAVEUP:
397                         newslave(msg);
398                         break;
399
400                 case TSP_ELECTION:
401                         if (fromnet->status == SLAVE) {
402                                 (void)gettimeofday(&ntime, 0);
403                                 electiontime = ntime.tv_sec + delay2;
404                                 fastelection = ntime.tv_sec + FASTTOUT;
405                                 seq = 0;
406                                 if (!good_host_name(msg->tsp_name)) {
407                                         syslog(LOG_NOTICE,
408                                                "suppress election of %s",
409                                                msg->tsp_name);
410                                         to.tsp_type = TSP_QUIT;
411                                         electiontime = fastelection;
412                                 } else if (cadr.s_addr != from.sin_addr.s_addr
413                                            && ntime.tv_sec < refusetime) {
414 /* if the candidate has to repeat itself, the old code would refuse it
415  * the second time.  That would prevent elections.
416  */
417                                         to.tsp_type = TSP_REFUSE;
418                                 } else {
419                                         cadr.s_addr = from.sin_addr.s_addr;
420                                         to.tsp_type = TSP_ACCEPT;
421                                         refusetime = ntime.tv_sec + 30;
422                                 }
423                                 taddr = from;
424                                 strlcpy(tname, msg->tsp_name, sizeof(tname));
425                                 strlcpy(to.tsp_name, hostname, 
426                                         sizeof(to.tsp_name));
427                                 answerdelay();
428                                 if (!acksend(&to, &taddr, tname,
429                                              TSP_ACK, 0, 0))
430                                         syslog(LOG_WARNING,
431                                              "no answer from candidate %s\n",
432                                                tname);
433
434                         } else {        /* fromnet->status == MASTER */
435                                 htp = addmach(msg->tsp_name, &from,fromnet);
436                                 to.tsp_type = TSP_QUIT;
437                                 strlcpy(to.tsp_name, hostname, 
438                                         sizeof(to.tsp_name));
439                                 if (!acksend(&to, &htp->addr, htp->name,
440                                              TSP_ACK, 0, htp->noanswer)) {
441                                         syslog(LOG_ERR,
442                                           "no reply from %s to ELECTION-QUIT",
443                                                htp->name);
444                                         (void)remmach(htp);
445                                 }
446                         }
447                         break;
448
449                 case TSP_CONFLICT:
450                         if (fromnet->status != MASTER)
451                                 break;
452                         /*
453                          * After a network partition, there can be
454                          * more than one master: the first slave to
455                          * come up will notify here the situation.
456                          */
457                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
458
459                         /* The other master often gets into the same state,
460                          * with boring results.
461                          */
462                         ntp = fromnet;  /* (acksend() can leave fromnet=0 */
463                         for (tries = 0; tries < 3; tries++) {
464                                 to.tsp_type = TSP_RESOLVE;
465                                 answer = acksend(&to, &ntp->dest_addr,
466                                                  ANYADDR, TSP_MASTERACK,
467                                                  ntp, 0);
468                                 if (answer == NULL)
469                                         break;
470                                 htp = addmach(answer->tsp_name,&from,ntp);
471                                 to.tsp_type = TSP_QUIT;
472                                 answer = acksend(&to, &htp->addr, htp->name,
473                                                  TSP_ACK, 0, htp->noanswer);
474                                 if (!answer) {
475                                         syslog(LOG_WARNING,
476                                   "conflict error: no reply from %s to QUIT",
477                                                 htp->name);
478                                         (void)remmach(htp);
479                                 }
480                         }
481                         masterup(ntp);
482                         break;
483
484                 case TSP_MSITE:
485                         if (!slavenet)
486                                 break;
487                         taddr = from;
488                         to.tsp_type = TSP_MSITEREQ;
489                         to.tsp_vers = TSPVERSION;
490                         to.tsp_seq = 0;
491                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
492                         answer = acksend(&to, &slavenet->dest_addr,
493                                          ANYADDR, TSP_ACK,
494                                          slavenet, 0);
495                         if (answer != NULL
496                             && good_host_name(answer->tsp_name)) {
497                                 setmaster(answer);
498                                 to.tsp_type = TSP_ACK;
499                                 strlcpy(to.tsp_name, answer->tsp_name,
500                                         sizeof(to.tsp_name));
501                                 bytenetorder(&to);
502                                 if (sendto(sock, (char *)&to,
503                                            sizeof(struct tsp), 0,
504                                            (struct sockaddr*)&taddr,
505                                            sizeof(taddr)) < 0) {
506                                         trace_sendto_err(taddr.sin_addr);
507                                 }
508                         }
509                         break;
510
511                 case TSP_MSITEREQ:
512                         break;
513
514                 case TSP_ACCEPT:
515                 case TSP_REFUSE:
516                 case TSP_RESOLVE:
517                         break;
518
519                 case TSP_QUIT:
520                         doquit(msg);            /* become a slave */
521                         break;
522
523                 case TSP_TEST:
524                         electiontime = 0;
525                         break;
526
527                 case TSP_LOOP:
528                         /* looking for loops of masters */
529                         if (!(status & MASTER))
530                                 break;
531                         if (fromnet->status == SLAVE) {
532                             if (!strcmp(msg->tsp_name, hostname)) {
533                                 /*
534                                  * Someone forwarded our message back to
535                                  * us.  There must be a loop.  Tell the
536                                  * master of this network to quit.
537                                  *
538                                  * The other master often gets into
539                                  * the same state, with boring results.
540                                  */
541                                 ntp = fromnet;
542                                 for (tries = 0; tries < 3; tries++) {
543                                     to.tsp_type = TSP_RESOLVE;
544                                     answer = acksend(&to, &ntp->dest_addr,
545                                                      ANYADDR, TSP_MASTERACK,
546                                                      ntp,0);
547                                     if (answer == NULL)
548                                         break;
549                                     taddr = from;
550                                     strlcpy(tname, answer->tsp_name,
551                                             sizeof(tname));
552                                     to.tsp_type = TSP_QUIT;
553                                     strlcpy(to.tsp_name, hostname,
554                                             sizeof(to.tsp_name));
555                                     if (!acksend(&to, &taddr, tname,
556                                                  TSP_ACK, 0, 1)) {
557                                         syslog(LOG_ERR,
558                                         "no reply from %s to slave LOOP-QUIT",
559                                                  tname);
560                                     } else {
561                                         electiontime = 0;
562                                     }
563                                 }
564                                 (void)gettimeofday(&ntime, 0);
565                                 looptime = ntime.tv_sec + FASTTOUT;
566                             } else {
567                                 if (msg->tsp_hopcnt-- < 1)
568                                     break;
569                                 bytenetorder(msg);
570                                 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
571                                     if (ntp->status == MASTER
572                                         && 0 > sendto(sock, (char *)msg,
573                                                       sizeof(struct tsp), 0,
574                                               (struct sockaddr*)&ntp->dest_addr,
575                                                       sizeof(ntp->dest_addr)))
576                                     trace_sendto_err(ntp->dest_addr.sin_addr);
577                                 }
578                             }
579                         } else {        /* fromnet->status == MASTER */
580                             /*
581                              * We should not have received this from a net
582                              * we are master on.  There must be two masters,
583                              * unless the packet was really from us.
584                              */
585                             if (from.sin_addr.s_addr
586                                 == fromnet->my_addr.s_addr) {
587                                 if (trace)
588                                     fprintf(fd,"discarding forwarded LOOP\n");
589                                 break;
590                             }
591
592                             /*
593                              * The other master often gets into the same
594                              * state, with boring results.
595                              */
596                             ntp = fromnet;
597                             for (tries = 0; tries < 3; tries++) {
598                                 to.tsp_type = TSP_RESOLVE;
599                                 answer = acksend(&to, &ntp->dest_addr,
600                                                  ANYADDR, TSP_MASTERACK,
601                                                 ntp,0);
602                                 if (!answer)
603                                         break;
604                                 htp = addmach(answer->tsp_name,
605                                               &from,ntp);
606                                 to.tsp_type = TSP_QUIT;
607                                 strlcpy(to.tsp_name, hostname,
608                                         sizeof(to.tsp_name));
609                                 if (!acksend(&to,&htp->addr,htp->name,
610                                              TSP_ACK, 0, htp->noanswer)) {
611                                         syslog(LOG_ERR,
612                                     "no reply from %s to master LOOP-QUIT",
613                                                htp->name);
614                                         (void)remmach(htp);
615                                 }
616                             }
617                             (void)gettimeofday(&ntime, 0);
618                             looptime = ntime.tv_sec + FASTTOUT;
619                         }
620                         break;
621                 default:
622                         if (trace) {
623                                 fprintf(fd, "garbage message: ");
624                                 print(msg, &from);
625                         }
626                         break;
627                 }
628         }
629         goto loop;
630 }
631
632
633 /*
634  * tell the world who our master is
635  */
636 static void
637 setmaster(struct tsp *msg)
638 {
639
640         if (slavenet
641             && (slavenet != old_slavenet
642                 || strcmp(msg->tsp_name, master_name)
643                 || old_status != status)) {
644                 strlcpy(master_name, msg->tsp_name, sizeof(master_name));
645                 old_slavenet = slavenet;
646                 old_status = status;
647
648                 if (status & MASTER) {
649                         syslog(LOG_NOTICE, "submaster to %s", master_name);
650                         if (trace)
651                                 fprintf(fd, "submaster to %s\n", master_name);
652
653                 } else {
654                         syslog(LOG_NOTICE, "slave to %s", master_name);
655                         if (trace)
656                                 fprintf(fd, "slave to %s\n", master_name);
657                 }
658         }
659 }
660
661
662
663 /*
664  * handle date change request on a slave
665  */
666 static void
667 schgdate(struct tsp *msg, char *newdate)
668 {
669         struct tsp to;
670         u_short seq;
671         struct sockaddr_in taddr;
672         struct timeval otime;
673
674         if (!slavenet)
675                 return;                 /* no where to forward */
676
677         taddr = from;
678         seq = msg->tsp_seq;
679
680         syslog(LOG_INFO,
681                "forwarding date change by %s to %s",
682                msg->tsp_name, newdate);
683
684         /* adjust time for residence on the queue */
685         (void)gettimeofday(&otime, 0);
686         adj_msg_time(msg, &otime);
687
688         to.tsp_type = TSP_SETDATEREQ;
689         to.tsp_time = msg->tsp_time;
690         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
691         if (!acksend(&to, &slavenet->dest_addr,
692                      ANYADDR, TSP_DATEACK,
693                      slavenet, 0))
694                 return;                 /* no answer */
695
696         xmit(TSP_DATEACK, seq, &taddr);
697 }
698
699
700 /*
701  * Used before answering a broadcast message to avoid network
702  * contention and likely collisions.
703  */
704 static void
705 answerdelay(void)
706 {
707
708 #ifdef sgi
709         sginap(delay1);
710 #else
711         struct timeval timeout;
712
713         timeout.tv_sec = 0;
714         timeout.tv_usec = delay1;
715
716         (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
717             &timeout);
718         return;
719 #endif /* sgi */
720 }