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