]> git.saurik.com Git - apple/network_cmds.git/blob - timed.tproj/timed.tproj/timed.c
95d440a302e06945d4d92e4d73ab85dfeec2dc2b
[apple/network_cmds.git] / timed.tproj / timed.tproj / timed.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*-
26 * Copyright (c) 1985, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58 #ifndef lint
59 static char copyright[] =
60 "@(#) Copyright (c) 1985, 1993\n\
61 The Regents of the University of California. All rights reserved.\n";
62 #endif /* not lint */
63
64 #ifndef lint
65 static char sccsid[] = "@(#)timed.c 8.2 (Berkeley) 3/26/95";
66 #endif /* not lint */
67
68 #ifdef sgi
69 #ident "$Revision: 1.1.1.1 $"
70 #endif /* sgi */
71
72 #define TSPTYPES
73 #include "globals.h"
74 #include <net/if.h>
75 #include <sys/file.h>
76 #include <sys/ioctl.h>
77 #include <setjmp.h>
78 #include "pathnames.h"
79 #include <math.h>
80 #include <sys/types.h>
81 #include <sys/times.h>
82 #ifdef sgi
83 #include <unistd.h>
84 #include <sys/syssgi.h>
85 #include <sys/schedctl.h>
86 #endif /* sgi */
87
88 int trace = 0;
89 int sock, sock_raw = -1;
90 int status = 0;
91 u_short sequence; /* sequence number */
92 long delay1;
93 long delay2;
94
95 int nslavenets; /* nets were I could be a slave */
96 int nmasternets; /* nets were I could be a master */
97 int nignorednets; /* ignored nets */
98 int nnets; /* nets I am connected to */
99
100 FILE *fd; /* trace file FD */
101
102 jmp_buf jmpenv;
103
104 struct netinfo *nettab = 0;
105 struct netinfo *slavenet;
106 int Mflag;
107 int justquit = 0;
108 int debug;
109
110 static struct nets {
111 char *name;
112 long net;
113 struct nets *next;
114 } *nets = 0;
115
116 struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
117
118 static struct goodhost { /* hosts that we trust */
119 char name[MAXHOSTNAMELEN+1];
120 struct goodhost *next;
121 char perm;
122 } *goodhosts;
123
124 static char *goodgroup; /* net group of trusted hosts */
125 static void checkignorednets __P((void));
126 static void pickslavenet __P((struct netinfo *));
127 static void add_good_host __P((char *, int));
128
129 #ifdef sgi
130 char *timetrim_fn;
131 char *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n";
132 char *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;";
133 long timetrim;
134 double tot_adj, hr_adj; /* totals in nsec */
135 double tot_ticks, hr_ticks;
136
137 int bufspace = 60*1024;
138 #endif
139
140
141 /*
142 * The timedaemons synchronize the clocks of hosts in a local area network.
143 * One daemon runs as master, all the others as slaves. The master
144 * performs the task of computing clock differences and sends correction
145 * values to the slaves.
146 * Slaves start an election to choose a new master when the latter disappears
147 * because of a machine crash, network partition, or when killed.
148 * A resolution protocol is used to kill all but one of the masters
149 * that happen to exist in segments of a partitioned network when the
150 * network partition is fixed.
151 *
152 * Authors: Riccardo Gusella & Stefano Zatti
153 *
154 * overhauled at Silicon Graphics
155 */
156 int
157 main(argc, argv)
158 int argc;
159 char *argv[];
160 {
161 int on;
162 int ret;
163 int nflag, iflag;
164 struct timeval ntime;
165 struct servent *srvp;
166 char buf[BUFSIZ], *cp, *cplim;
167 struct ifconf ifc;
168 struct ifreq ifreq, ifreqf, *ifr;
169 register struct netinfo *ntp;
170 struct netinfo *ntip;
171 struct netinfo *savefromnet;
172 struct netent *nentp;
173 struct nets *nt;
174 static struct sockaddr_in server;
175 u_short port;
176 char c;
177 extern char *optarg;
178 extern int optind, opterr;
179 #ifdef sgi
180 FILE *timetrim_st;
181 #endif
182
183 #define IN_MSG "timed: -i and -n make no sense together\n"
184 #ifdef sgi
185 struct tms tms;
186 #define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp] [-P trimfile]\n"
187 #else
188 #ifdef HAVENIS
189 #define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n"
190 #else
191 #define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...]\n"
192 #endif /* HAVENIS */
193 #endif /* sgi */
194
195 #ifdef lint
196 ntip = NULL;
197 #endif
198
199 on = 1;
200 nflag = OFF;
201 iflag = OFF;
202
203 #ifdef sgi
204 if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) {
205 perror("timed: syssgi(GETTIMETRIM)");
206 timetrim = 0;
207 }
208 tot_ticks = hr_ticks = times(&tms);
209 #endif /* sgi */
210
211 opterr = 0;
212 while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != EOF) {
213 switch (c) {
214 case 'M':
215 Mflag = 1;
216 break;
217
218 case 't':
219 trace = 1;
220 break;
221
222 case 'n':
223 if (iflag) {
224 fprintf(stderr, IN_MSG);
225 exit(1);
226 } else {
227 nflag = ON;
228 addnetname(optarg);
229 }
230 break;
231
232 case 'i':
233 if (nflag) {
234 fprintf(stderr, IN_MSG);
235 exit(1);
236 } else {
237 iflag = ON;
238 addnetname(optarg);
239 }
240 break;
241
242 case 'F':
243 add_good_host(optarg,1);
244 while (optind < argc && argv[optind][0] != '-')
245 add_good_host(argv[optind++], 1);
246 break;
247
248 case 'd':
249 debug = 1;
250 break;
251 case 'G':
252 if (goodgroup != 0) {
253 fprintf(stderr,"timed: only one net group\n");
254 exit(1);
255 }
256 goodgroup = optarg;
257 break;
258 #ifdef sgi
259 case 'P':
260 timetrim_fn = optarg;
261 break;
262 #endif /* sgi */
263
264 default:
265 fprintf(stderr, USAGE);
266 exit(1);
267 break;
268 }
269 }
270 if (optind < argc) {
271 fprintf(stderr, USAGE);
272 exit(1);
273 }
274
275 #ifdef sgi
276 if (timetrim_fn == 0) {
277 ;
278 } else if (0 == (timetrim_st = fopen(timetrim_fn, "r+"))) {
279 if (errno != ENOENT) {
280 (void)fprintf(stderr,"timed: ");
281 perror(timetrim_fn);
282 timetrim_fn = 0;
283 }
284 } else {
285 int i;
286 long trim;
287 double adj, ticks;
288
289 i = fscanf(timetrim_st, timetrim_rpat,
290 &trim, &adj, &ticks);
291 if (i < 1
292 || trim > MAX_TRIM
293 || trim < -MAX_TRIM
294 || i == 2
295 || (i == 3
296 && trim != rint(adj*CLK_TCK/ticks))) {
297 if (trace && i != EOF)
298 (void)fprintf(stderr,
299 "timed: unrecognized contents in %s\n",
300 timetrim_fn);
301 } else {
302 if (0 > syssgi(SGI_SETTIMETRIM,
303 trim)) {
304 perror("timed: syssgi(SETTIMETRIM)");
305 } else {
306 timetrim = trim;
307 }
308 if (i == 3)
309 tot_ticks -= ticks;
310 }
311 (void)fclose(timetrim_st);
312 }
313 #endif /* sgi */
314
315 /* If we care about which machine is the master, then we must
316 * be willing to be a master
317 */
318 if (0 != goodgroup || 0 != goodhosts)
319 Mflag = 1;
320
321 if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
322 perror("gethostname");
323 exit(1);
324 }
325 self.l_bak = &self;
326 self.l_fwd = &self;
327 self.h_bak = &self;
328 self.h_fwd = &self;
329 self.head = 1;
330 self.good = 1;
331
332 if (goodhosts != 0) /* trust ourself */
333 add_good_host(hostname,1);
334
335 srvp = getservbyname("timed", "udp");
336 if (srvp == 0) {
337 fprintf(stderr, "unknown service 'timed/udp'\n");
338 exit(1);
339 }
340 port = srvp->s_port;
341 server.sin_addr.s_addr = INADDR_ANY;
342 server.sin_port = srvp->s_port;
343 server.sin_family = AF_INET;
344 sock = socket(AF_INET, SOCK_DGRAM, 0);
345 if (sock < 0) {
346 perror("socket");
347 exit(1);
348 }
349 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
350 sizeof(on)) < 0) {
351 perror("setsockopt");
352 exit(1);
353 }
354 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
355 if (errno == EADDRINUSE)
356 fprintf(stderr,"timed: time daemon already running\n");
357 else
358 perror("bind");
359 exit(1);
360 }
361 #ifdef sgi
362 /*
363 * handle many slaves with our buffer
364 */
365 if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace,
366 sizeof(bufspace))) {
367 perror("setsockopt");
368 exit(1);
369 }
370 #endif /* sgi */
371
372 /* choose a unique seed for random number generation */
373 (void)gettimeofday(&ntime, 0);
374 srandom(ntime.tv_sec + ntime.tv_usec);
375
376 sequence = random(); /* initial seq number */
377
378 #ifndef sgi
379 /* rounds kernel variable time to multiple of 5 ms. */
380 ntime.tv_sec = 0;
381 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
382 (void)adjtime(&ntime, (struct timeval *)0);
383 #endif /* sgi */
384
385 for (nt = nets; nt; nt = nt->next) {
386 nentp = getnetbyname(nt->name);
387 if (nentp == 0) {
388 nt->net = inet_network(nt->name);
389 if (nt->net != INADDR_NONE)
390 nentp = getnetbyaddr(nt->net, AF_INET);
391 }
392 if (nentp != 0) {
393 nt->net = nentp->n_net;
394 } else if (nt->net == INADDR_NONE) {
395 fprintf(stderr, "timed: unknown net %s\n", nt->name);
396 exit(1);
397 } else if (nt->net == INADDR_ANY) {
398 fprintf(stderr, "timed: bad net %s\n", nt->name);
399 exit(1);
400 } else {
401 fprintf(stderr,
402 "timed: warning: %s unknown in /etc/networks\n",
403 nt->name);
404 }
405
406 if (0 == (nt->net & 0xff000000))
407 nt->net <<= 8;
408 if (0 == (nt->net & 0xff000000))
409 nt->net <<= 8;
410 if (0 == (nt->net & 0xff000000))
411 nt->net <<= 8;
412 }
413 ifc.ifc_len = sizeof(buf);
414 ifc.ifc_buf = buf;
415 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
416 perror("timed: get interface configuration");
417 exit(1);
418 }
419 ntp = NULL;
420 #ifdef sgi
421 #define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */
422 #else
423 #define size(p) max((p).sa_len, sizeof(p))
424 #endif
425 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
426 for (cp = buf; cp < cplim;
427 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
428 ifr = (struct ifreq *)cp;
429 if (ifr->ifr_addr.sa_family != AF_INET)
430 continue;
431 if (!ntp)
432 ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
433 bzero(ntp,sizeof(*ntp));
434 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
435 ntp->status = NOMASTER;
436 ifreq = *ifr;
437 ifreqf = *ifr;
438
439 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
440 perror("get interface flags");
441 continue;
442 }
443 if ((ifreqf.ifr_flags & IFF_UP) == 0)
444 continue;
445 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
446 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
447 continue;
448 }
449
450
451 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
452 perror("get netmask");
453 continue;
454 }
455 ntp->mask = ((struct sockaddr_in *)
456 &ifreq.ifr_addr)->sin_addr.s_addr;
457
458 if (ifreqf.ifr_flags & IFF_BROADCAST) {
459 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
460 perror("get broadaddr");
461 continue;
462 }
463 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
464 /* What if the broadcast address is all ones?
465 * So we cannot just mask ntp->dest_addr. */
466 ntp->net = ntp->my_addr;
467 ntp->net.s_addr &= ntp->mask;
468 } else {
469 if (ioctl(sock, SIOCGIFDSTADDR,
470 (char *)&ifreq) < 0) {
471 perror("get destaddr");
472 continue;
473 }
474 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
475 ntp->net = ntp->dest_addr.sin_addr;
476 }
477
478 ntp->dest_addr.sin_port = port;
479
480 for (nt = nets; nt; nt = nt->next) {
481 if (ntp->net.s_addr == nt->net)
482 break;
483 }
484 if (nflag && !nt || iflag && nt)
485 continue;
486
487 ntp->next = NULL;
488 if (nettab == NULL) {
489 nettab = ntp;
490 } else {
491 ntip->next = ntp;
492 }
493 ntip = ntp;
494 ntp = NULL;
495 }
496 if (ntp)
497 (void) free((char *)ntp);
498 if (nettab == NULL) {
499 fprintf(stderr, "timed: no network usable\n");
500 exit(1);
501 }
502
503
504 #ifdef sgi
505 (void)schedctl(RENICE,0,10); /* run fast to get good time */
506
507 /* ticks to delay before responding to a broadcast */
508 delay1 = casual(0, CLK_TCK/10);
509 #else
510
511 /* microseconds to delay before responding to a broadcast */
512 delay1 = casual(1, 100*1000);
513 #endif /* sgi */
514
515 /* election timer delay in secs. */
516 delay2 = casual(MINTOUT, MAXTOUT);
517
518
519 #ifdef sgi
520 (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1);
521 #else
522 if (!debug)
523 daemon(debug, 0);
524 #endif /* sgi */
525
526 if (trace)
527 traceon();
528 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
529
530 /*
531 * keep returning here
532 */
533 ret = setjmp(jmpenv);
534 savefromnet = fromnet;
535 setstatus();
536
537 if (Mflag) {
538 switch (ret) {
539
540 case 0:
541 checkignorednets();
542 pickslavenet(0);
543 break;
544 case 1:
545 /* Just lost our master */
546 if (slavenet != 0)
547 slavenet->status = election(slavenet);
548 if (!slavenet || slavenet->status == MASTER) {
549 checkignorednets();
550 pickslavenet(0);
551 } else {
552 makeslave(slavenet); /* prune extras */
553 }
554 break;
555
556 case 2:
557 /* Just been told to quit */
558 justquit = 1;
559 pickslavenet(savefromnet);
560 break;
561 }
562
563 setstatus();
564 if (!(status & MASTER) && sock_raw != -1) {
565 /* sock_raw is not being used now */
566 (void)close(sock_raw);
567 sock_raw = -1;
568 }
569
570 if (status == MASTER)
571 master();
572 else
573 slave();
574
575 } else {
576 if (sock_raw != -1) {
577 (void)close(sock_raw);
578 sock_raw = -1;
579 }
580
581 if (ret) {
582 /* we just lost our master or were told to quit */
583 justquit = 1;
584 }
585 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
586 if (ntp->status == MASTER)
587 rmnetmachs(ntp);
588 ntp->status = NOMASTER;
589 }
590 checkignorednets();
591 pickslavenet(0);
592 setstatus();
593
594 slave();
595 }
596 /* NOTREACHED */
597 #ifdef lint
598 return(0);
599 #endif
600 }
601
602 /*
603 * suppress an upstart, untrustworthy, self-appointed master
604 */
605 void
606 suppress(addr, name,net)
607 struct sockaddr_in *addr;
608 char *name;
609 struct netinfo *net;
610 {
611 struct sockaddr_in tgt;
612 char tname[MAXHOSTNAMELEN];
613 struct tsp msg;
614 static struct timeval wait;
615
616 if (trace)
617 fprintf(fd, "suppress: %s\n", name);
618 tgt = *addr;
619 (void)strcpy(tname, name);
620
621 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
622 if (trace)
623 fprintf(fd, "suppress:\tdiscarded packet from %s\n",
624 name);
625 }
626
627 syslog(LOG_NOTICE, "suppressing false master %s", tname);
628 msg.tsp_type = TSP_QUIT;
629 (void)strcpy(msg.tsp_name, hostname);
630 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
631 }
632
633 void
634 lookformaster(ntp)
635 struct netinfo *ntp;
636 {
637 struct tsp resp, conflict, *answer;
638 struct timeval ntime;
639 char mastername[MAXHOSTNAMELEN];
640 struct sockaddr_in masteraddr;
641
642 get_goodgroup(0);
643 ntp->status = SLAVE;
644
645 /* look for master */
646 resp.tsp_type = TSP_MASTERREQ;
647 (void)strcpy(resp.tsp_name, hostname);
648 answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
649 TSP_MASTERACK, ntp, 0);
650 if (answer != 0 && !good_host_name(answer->tsp_name)) {
651 suppress(&from, answer->tsp_name, ntp);
652 ntp->status = NOMASTER;
653 answer = 0;
654 }
655 if (answer == 0) {
656 /*
657 * Various conditions can cause conflict: races between
658 * two just started timedaemons when no master is
659 * present, or timedaemons started during an election.
660 * A conservative approach is taken. Give up and became a
661 * slave, postponing election of a master until first
662 * timer expires.
663 */
664 ntime.tv_sec = ntime.tv_usec = 0;
665 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
666 if (answer != 0) {
667 if (!good_host_name(answer->tsp_name)) {
668 suppress(&from, answer->tsp_name, ntp);
669 ntp->status = NOMASTER;
670 }
671 return;
672 }
673
674 ntime.tv_sec = ntime.tv_usec = 0;
675 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
676 if (answer != 0) {
677 if (!good_host_name(answer->tsp_name)) {
678 suppress(&from, answer->tsp_name, ntp);
679 ntp->status = NOMASTER;
680 }
681 return;
682 }
683
684 ntime.tv_sec = ntime.tv_usec = 0;
685 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
686 if (answer != 0) {
687 if (!good_host_name(answer->tsp_name)) {
688 suppress(&from, answer->tsp_name, ntp);
689 ntp->status = NOMASTER;
690 }
691 return;
692 }
693
694 if (Mflag)
695 ntp->status = MASTER;
696 else
697 ntp->status = NOMASTER;
698 return;
699 }
700
701 ntp->status = SLAVE;
702 (void)strcpy(mastername, answer->tsp_name);
703 masteraddr = from;
704
705 /*
706 * If network has been partitioned, there might be other
707 * masters; tell the one we have just acknowledged that
708 * it has to gain control over the others.
709 */
710 ntime.tv_sec = 0;
711 ntime.tv_usec = 300000;
712 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
713 /*
714 * checking also not to send CONFLICT to ack'ed master
715 * due to duplicated MASTERACKs
716 */
717 if (answer != NULL &&
718 strcmp(answer->tsp_name, mastername) != 0) {
719 conflict.tsp_type = TSP_CONFLICT;
720 (void)strcpy(conflict.tsp_name, hostname);
721 if (!acksend(&conflict, &masteraddr, mastername,
722 TSP_ACK, 0, 0)) {
723 syslog(LOG_ERR,
724 "error on sending TSP_CONFLICT");
725 }
726 }
727 }
728
729 /*
730 * based on the current network configuration, set the status, and count
731 * networks;
732 */
733 void
734 setstatus()
735 {
736 struct netinfo *ntp;
737
738 status = 0;
739 nmasternets = nslavenets = nnets = nignorednets = 0;
740 if (trace)
741 fprintf(fd, "Net status:\n");
742 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
743 switch ((int)ntp->status) {
744 case MASTER:
745 nmasternets++;
746 break;
747 case SLAVE:
748 nslavenets++;
749 break;
750 case NOMASTER:
751 case IGNORE:
752 nignorednets++;
753 break;
754 }
755 if (trace) {
756 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
757 switch ((int)ntp->status) {
758 case NOMASTER:
759 fprintf(fd, "NOMASTER\n");
760 break;
761 case MASTER:
762 fprintf(fd, "MASTER\n");
763 break;
764 case SLAVE:
765 fprintf(fd, "SLAVE\n");
766 break;
767 case IGNORE:
768 fprintf(fd, "IGNORE\n");
769 break;
770 default:
771 fprintf(fd, "invalid state %d\n",
772 (int)ntp->status);
773 break;
774 }
775 }
776 nnets++;
777 status |= ntp->status;
778 }
779 status &= ~IGNORE;
780 if (trace)
781 fprintf(fd,
782 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%d\n",
783 nnets, nmasternets, nslavenets, nignorednets, delay2);
784 }
785
786 void
787 makeslave(net)
788 struct netinfo *net;
789 {
790 register struct netinfo *ntp;
791
792 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
793 if (ntp->status == SLAVE && ntp != net)
794 ntp->status = IGNORE;
795 }
796 slavenet = net;
797 }
798
799 /*
800 * Try to become master over ignored nets..
801 */
802 static void
803 checkignorednets()
804 {
805 register struct netinfo *ntp;
806
807 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
808 if (!Mflag && ntp->status == SLAVE)
809 break;
810
811 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
812 lookformaster(ntp);
813 if (!Mflag && ntp->status == SLAVE)
814 break;
815 }
816 }
817 }
818
819 /*
820 * choose a good network on which to be a slave
821 * The ignored networks must have already been checked.
822 * Take a hint about for a good network.
823 */
824 static void
825 pickslavenet(ntp)
826 struct netinfo *ntp;
827 {
828 if (slavenet != 0 && slavenet->status == SLAVE) {
829 makeslave(slavenet); /* prune extras */
830 return;
831 }
832
833 if (ntp == 0 || ntp->status != SLAVE) {
834 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
835 if (ntp->status == SLAVE)
836 break;
837 }
838 }
839 makeslave(ntp);
840 }
841
842 /*
843 * returns a random number in the range [inf, sup]
844 */
845 long
846 casual(inf, sup)
847 long inf, sup;
848 {
849 double value;
850
851 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
852 return(inf + (sup - inf)*value);
853 }
854
855 char *
856 date()
857 {
858 #ifdef sgi
859 struct timeval tv;
860 static char tm[32];
861
862 (void)gettimeofday(&tv, (struct timezone *)0);
863 (void)cftime(tm, "%D %T", &tv.tv_sec);
864 return (tm);
865 #else
866 struct timeval tv;
867
868 (void)gettimeofday(&tv, (struct timezone *)0);
869 return (ctime(&tv.tv_sec));
870 #endif /* sgi */
871 }
872
873 void
874 addnetname(name)
875 char *name;
876 {
877 register struct nets **netlist = &nets;
878
879 while (*netlist)
880 netlist = &((*netlist)->next);
881 *netlist = (struct nets *)malloc(sizeof **netlist);
882 if (*netlist == 0) {
883 fprintf(stderr,"malloc failed\n");
884 exit(1);
885 }
886 bzero((char *)*netlist, sizeof(**netlist));
887 (*netlist)->name = name;
888 }
889
890 /* note a host as trustworthy */
891 static void
892 add_good_host(name, perm)
893 char *name;
894 int perm; /* 1=not part of the netgroup */
895 {
896 register struct goodhost *ghp;
897 register struct hostent *hentp;
898
899 ghp = (struct goodhost*)malloc(sizeof(*ghp));
900 if (!ghp) {
901 syslog(LOG_ERR, "malloc failed");
902 exit(1);
903 }
904
905 bzero((char*)ghp, sizeof(*ghp));
906 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
907 ghp->next = goodhosts;
908 ghp->perm = perm;
909 goodhosts = ghp;
910
911 hentp = gethostbyname(name);
912 if (0 == hentp && perm)
913 (void)fprintf(stderr, "unknown host %s\n", name);
914 }
915
916
917 /* update our image of the net-group of trustworthy hosts
918 */
919 void
920 get_goodgroup(force)
921 int force;
922 {
923 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
924 static unsigned long last_update = -NG_DELAY;
925 unsigned long new_update;
926 struct hosttbl *htp;
927 struct goodhost *ghp, **ghpp;
928 char *mach, *usr, *dom;
929 struct tms tm;
930
931
932 /* if no netgroup, then we are finished */
933 if (goodgroup == 0 || !Mflag)
934 return;
935
936 /* Do not chatter with the netgroup master too often.
937 */
938 new_update = times(&tm);
939 if (new_update < last_update + NG_DELAY
940 && !force)
941 return;
942 last_update = new_update;
943
944 /* forget the old temporary entries */
945 ghpp = &goodhosts;
946 while (0 != (ghp = *ghpp)) {
947 if (!ghp->perm) {
948 *ghpp = ghp->next;
949 free((char*)ghp);
950 } else {
951 ghpp = &ghp->next;
952 }
953 }
954
955 #ifdef HAVENIS
956 /* quit now if we are not one of the trusted masters
957 */
958 if (!innetgr(goodgroup, &hostname[0], 0,0)) {
959 if (trace)
960 (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
961 &hostname[0], goodgroup);
962 return;
963 }
964 if (trace)
965 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
966 &hostname[0], goodgroup);
967
968 /* mark the entire netgroup as trusted */
969 (void)setnetgrent(goodgroup);
970 while (getnetgrent(&mach,&usr,&dom)) {
971 if (0 != mach)
972 add_good_host(mach,0);
973 }
974 (void)endnetgrent();
975
976 /* update list of slaves */
977 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
978 htp->good = good_host_name(&htp->name[0]);
979 }
980 #endif /* HAVENIS */
981 }
982
983
984 /* see if a machine is trustworthy
985 */
986 int /* 1=trust hp to change our date */
987 good_host_name(name)
988 char *name;
989 {
990 register struct goodhost *ghp = goodhosts;
991 register char c;
992
993 if (!ghp || !Mflag) /* trust everyone if no one named */
994 return 1;
995
996 c = *name;
997 do {
998 if (c == ghp->name[0]
999 && !strcasecmp(name, ghp->name))
1000 return 1; /* found him, so say so */
1001 } while (0 != (ghp = ghp->next));
1002
1003 if (!strcasecmp(name,hostname)) /* trust ourself */
1004 return 1;
1005
1006 return 0; /* did not find him */
1007 }