2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
33 * @(#) Copyright (c) 1985, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)timed.c 8.1 (Berkeley) 6/6/93
35 * $FreeBSD: src/usr.sbin/timed/timed/timed.c,v 1.9 1999/08/28 01:20:19 peter Exp $
36 * $DragonFly: src/usr.sbin/timed/timed/timed.c,v 1.2 2003/06/17 04:30:03 dillon Exp $
43 #include <sys/ioctl.h>
45 #include "pathnames.h"
47 #include <sys/types.h>
48 #include <sys/times.h>
51 #include <sys/syssgi.h>
52 #include <sys/schedctl.h>
56 int sock, sock_raw = -1;
58 u_short sequence; /* sequence number */
62 int nslavenets; /* nets were I could be a slave */
63 int nmasternets; /* nets were I could be a master */
64 int nignorednets; /* ignored nets */
65 int nnets; /* nets I am connected to */
67 FILE *fd; /* trace file FD */
71 struct netinfo *nettab = 0;
72 struct netinfo *slavenet;
83 struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
85 static struct goodhost { /* hosts that we trust */
86 char name[MAXHOSTNAMELEN];
87 struct goodhost *next;
91 static char *goodgroup; /* net group of trusted hosts */
92 static void checkignorednets __P((void));
93 static void pickslavenet __P((struct netinfo *));
94 static void add_good_host __P((char *, int));
98 char *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n";
99 char *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;";
101 double tot_adj, hr_adj; /* totals in nsec */
102 double tot_ticks, hr_ticks;
104 int bufspace = 60*1024;
107 static void usage __P((void));
110 * The timedaemons synchronize the clocks of hosts in a local area network.
111 * One daemon runs as master, all the others as slaves. The master
112 * performs the task of computing clock differences and sends correction
113 * values to the slaves.
114 * Slaves start an election to choose a new master when the latter disappears
115 * because of a machine crash, network partition, or when killed.
116 * A resolution protocol is used to kill all but one of the masters
117 * that happen to exist in segments of a partitioned network when the
118 * network partition is fixed.
120 * Authors: Riccardo Gusella & Stefano Zatti
122 * overhauled at Silicon Graphics
132 struct timeval ntime;
133 struct servent *srvp;
134 char buf[BUFSIZ], *cp, *cplim;
136 struct ifreq ifreq, ifreqf, *ifr;
137 register struct netinfo *ntp;
138 struct netinfo *ntip;
139 struct netinfo *savefromnet;
140 struct netent *nentp;
142 struct sockaddr_in server;
162 if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) {
163 warn("syssgi(GETTIMETRIM)");
166 tot_ticks = hr_ticks = times(&tms);
170 while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
182 errx(1, "-i and -n make no sense together");
191 errx(1, "-i and -n make no sense together");
199 add_good_host(optarg,1);
200 while (optind < argc && argv[optind][0] != '-')
201 add_good_host(argv[optind++], 1);
209 errx(1, "only one net group");
214 timetrim_fn = optarg;
215 timetrim_st = fopen(timetrim_fn, "r+");
216 if (0 == timetrim_st) {
217 if (errno != ENOENT) {
218 warn("%s", timetrim_fn);
226 i = fscanf(timetrim_st, timetrim_rpat,
227 &trim, &adj, &ticks);
233 && trim != rint(adj*CLK_TCK/ticks))) {
234 if (trace && i != EOF)
236 "unrecognized contents in %s",
239 if (0 > syssgi(SGI_SETTIMETRIM,
241 warn("syssgi(SETTIMETRIM)");
250 (void)fclose(timetrim_st);
263 /* If we care about which machine is the master, then we must
264 * be willing to be a master
266 if (0 != goodgroup || 0 != goodhosts)
269 if (gethostname(hostname, sizeof(hostname) - 1) < 0)
270 err(1, "gethostname");
278 if (goodhosts != 0) /* trust ourself */
279 add_good_host(hostname,1);
281 srvp = getservbyname("timed", "udp");
283 errx(1, "unknown service 'timed/udp'");
285 bzero(&server, sizeof(struct sockaddr_in));
286 server.sin_port = srvp->s_port;
287 server.sin_family = AF_INET;
288 sock = socket(AF_INET, SOCK_DGRAM, 0);
291 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
293 err(1, "setsockopt");
294 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
295 if (errno == EADDRINUSE)
296 warnx("time daemon already running");
303 * handle many slaves with our buffer
305 if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace,
307 err(1, "setsockopt");
310 /* choose a unique seed for random number generation */
311 (void)gettimeofday(&ntime, 0);
312 srandom(ntime.tv_sec + ntime.tv_usec);
314 sequence = random(); /* initial seq number */
317 /* rounds kernel variable time to multiple of 5 ms. */
319 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
320 (void)adjtime(&ntime, (struct timeval *)0);
323 for (nt = nets; nt; nt = nt->next) {
324 nentp = getnetbyname(nt->name);
326 nt->net = inet_network(nt->name);
327 if (nt->net != INADDR_NONE)
328 nentp = getnetbyaddr(nt->net, AF_INET);
331 nt->net = nentp->n_net;
332 } else if (nt->net == INADDR_NONE) {
333 errx(1, "unknown net %s", nt->name);
334 } else if (nt->net == INADDR_ANY) {
335 errx(1, "bad net %s", nt->name);
337 warnx("warning: %s unknown in /etc/networks",
341 if (0 == (nt->net & 0xff000000))
343 if (0 == (nt->net & 0xff000000))
345 if (0 == (nt->net & 0xff000000))
348 ifc.ifc_len = sizeof(buf);
350 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
351 err(1, "get interface configuration");
354 #define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */
356 #define size(p) max((p).sa_len, sizeof(p))
358 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
359 for (cp = buf; cp < cplim;
360 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
361 ifr = (struct ifreq *)cp;
362 if (ifr->ifr_addr.sa_family != AF_INET)
365 ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
366 bzero(ntp,sizeof(*ntp));
367 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
368 ntp->status = NOMASTER;
372 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
373 warn("get interface flags");
376 if ((ifreqf.ifr_flags & IFF_UP) == 0)
378 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
379 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
384 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
388 ntp->mask = ((struct sockaddr_in *)
389 &ifreq.ifr_addr)->sin_addr.s_addr;
391 if (ifreqf.ifr_flags & IFF_BROADCAST) {
392 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
393 warn("get broadaddr");
396 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
397 /* What if the broadcast address is all ones?
398 * So we cannot just mask ntp->dest_addr. */
399 ntp->net = ntp->my_addr;
400 ntp->net.s_addr &= ntp->mask;
402 if (ioctl(sock, SIOCGIFDSTADDR,
403 (char *)&ifreq) < 0) {
404 warn("get destaddr");
407 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
408 ntp->net = ntp->dest_addr.sin_addr;
411 ntp->dest_addr.sin_port = port;
413 for (nt = nets; nt; nt = nt->next) {
414 if (ntp->net.s_addr == htonl(nt->net))
417 if ((nflag && !nt) || (iflag && nt))
421 if (nettab == NULL) {
430 (void) free((char *)ntp);
432 errx(1, "no network usable");
436 (void)schedctl(RENICE,0,10); /* run fast to get good time */
438 /* ticks to delay before responding to a broadcast */
439 delay1 = casual(0, CLK_TCK/10);
442 /* microseconds to delay before responding to a broadcast */
443 delay1 = casual(1, 100*1000);
446 /* election timer delay in secs. */
447 delay2 = casual(MINTOUT, MAXTOUT);
451 (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1);
459 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
462 * keep returning here
464 ret = setjmp(jmpenv);
465 savefromnet = fromnet;
476 /* Just lost our master */
478 slavenet->status = election(slavenet);
479 if (!slavenet || slavenet->status == MASTER) {
483 makeslave(slavenet); /* prune extras */
488 /* Just been told to quit */
490 pickslavenet(savefromnet);
495 if (!(status & MASTER) && sock_raw != -1) {
496 /* sock_raw is not being used now */
497 (void)close(sock_raw);
501 if (status == MASTER)
507 if (sock_raw != -1) {
508 (void)close(sock_raw);
513 /* we just lost our master or were told to quit */
516 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
517 if (ntp->status == MASTER)
519 ntp->status = NOMASTER;
535 fprintf(stderr, "%s\n%s\n",
536 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]",
537 " [-G netgp] [-P trimfile]");
541 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
544 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
551 * suppress an upstart, untrustworthy, self-appointed master
554 suppress(addr, name,net)
555 struct sockaddr_in *addr;
559 struct sockaddr_in tgt;
560 char tname[MAXHOSTNAMELEN];
562 static struct timeval wait;
565 fprintf(fd, "suppress: %s\n", name);
567 (void)strcpy(tname, name);
569 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
571 fprintf(fd, "suppress:\tdiscarded packet from %s\n",
575 syslog(LOG_NOTICE, "suppressing false master %s", tname);
576 msg.tsp_type = TSP_QUIT;
577 (void)strcpy(msg.tsp_name, hostname);
578 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
585 struct tsp resp, conflict, *answer;
586 struct timeval ntime;
587 char mastername[MAXHOSTNAMELEN];
588 struct sockaddr_in masteraddr;
593 /* look for master */
594 resp.tsp_type = TSP_MASTERREQ;
595 (void)strcpy(resp.tsp_name, hostname);
596 answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
597 TSP_MASTERACK, ntp, 0);
598 if (answer != 0 && !good_host_name(answer->tsp_name)) {
599 suppress(&from, answer->tsp_name, ntp);
600 ntp->status = NOMASTER;
605 * Various conditions can cause conflict: races between
606 * two just started timedaemons when no master is
607 * present, or timedaemons started during an election.
608 * A conservative approach is taken. Give up and became a
609 * slave, postponing election of a master until first
612 ntime.tv_sec = ntime.tv_usec = 0;
613 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
615 if (!good_host_name(answer->tsp_name)) {
616 suppress(&from, answer->tsp_name, ntp);
617 ntp->status = NOMASTER;
622 ntime.tv_sec = ntime.tv_usec = 0;
623 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
625 if (!good_host_name(answer->tsp_name)) {
626 suppress(&from, answer->tsp_name, ntp);
627 ntp->status = NOMASTER;
632 ntime.tv_sec = ntime.tv_usec = 0;
633 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
635 if (!good_host_name(answer->tsp_name)) {
636 suppress(&from, answer->tsp_name, ntp);
637 ntp->status = NOMASTER;
643 ntp->status = MASTER;
645 ntp->status = NOMASTER;
650 (void)strcpy(mastername, answer->tsp_name);
654 * If network has been partitioned, there might be other
655 * masters; tell the one we have just acknowledged that
656 * it has to gain control over the others.
659 ntime.tv_usec = 300000;
660 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
662 * checking also not to send CONFLICT to ack'ed master
663 * due to duplicated MASTERACKs
665 if (answer != NULL &&
666 strcmp(answer->tsp_name, mastername) != 0) {
667 conflict.tsp_type = TSP_CONFLICT;
668 (void)strcpy(conflict.tsp_name, hostname);
669 if (!acksend(&conflict, &masteraddr, mastername,
672 "error on sending TSP_CONFLICT");
678 * based on the current network configuration, set the status, and count
687 nmasternets = nslavenets = nnets = nignorednets = 0;
689 fprintf(fd, "Net status:\n");
690 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
691 switch ((int)ntp->status) {
704 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
705 switch ((int)ntp->status) {
707 fprintf(fd, "NOMASTER\n");
710 fprintf(fd, "MASTER\n");
713 fprintf(fd, "SLAVE\n");
716 fprintf(fd, "IGNORE\n");
719 fprintf(fd, "invalid state %d\n",
725 status |= ntp->status;
730 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
731 nnets, nmasternets, nslavenets, nignorednets, delay2);
738 register struct netinfo *ntp;
740 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
741 if (ntp->status == SLAVE && ntp != net)
742 ntp->status = IGNORE;
748 * Try to become master over ignored nets..
753 register struct netinfo *ntp;
755 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
756 if (!Mflag && ntp->status == SLAVE)
759 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
761 if (!Mflag && ntp->status == SLAVE)
768 * choose a good network on which to be a slave
769 * The ignored networks must have already been checked.
770 * Take a hint about for a good network.
776 if (slavenet != 0 && slavenet->status == SLAVE) {
777 makeslave(slavenet); /* prune extras */
781 if (ntp == 0 || ntp->status != SLAVE) {
782 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
783 if (ntp->status == SLAVE)
791 * returns a random number in the range [inf, sup]
799 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
800 return(inf + (sup - inf)*value);
810 (void)gettimeofday(&tv, (struct timezone *)0);
811 (void)cftime(tm, "%D %T", &tv.tv_sec);
817 (void)gettimeofday(&tv, (struct timezone *)0);
819 return (ctime(&tv_sec));
827 register struct nets **netlist = &nets;
830 netlist = &((*netlist)->next);
831 *netlist = (struct nets *)malloc(sizeof **netlist);
833 errx(1, "malloc failed");
834 bzero((char *)*netlist, sizeof(**netlist));
835 (*netlist)->name = name;
838 /* note a host as trustworthy */
840 add_good_host(name, perm)
842 int perm; /* 1=not part of the netgroup */
844 register struct goodhost *ghp;
845 register struct hostent *hentp;
847 ghp = (struct goodhost*)malloc(sizeof(*ghp));
849 syslog(LOG_ERR, "malloc failed");
853 bzero((char*)ghp, sizeof(*ghp));
854 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
855 ghp->next = goodhosts;
859 hentp = gethostbyname(name);
860 if (0 == hentp && perm)
861 warnx("unknown host %s", name);
865 /* update our image of the net-group of trustworthy hosts
871 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
872 static unsigned long last_update = -NG_DELAY;
873 unsigned long new_update;
874 struct goodhost *ghp, **ghpp;
877 char *mach, *usr, *dom;
882 /* if no netgroup, then we are finished */
883 if (goodgroup == 0 || !Mflag)
886 /* Do not chatter with the netgroup master too often.
888 new_update = times(&tm);
889 if (new_update < last_update + NG_DELAY
892 last_update = new_update;
894 /* forget the old temporary entries */
896 while (0 != (ghp = *ghpp)) {
906 /* quit now if we are not one of the trusted masters
908 if (!innetgr(goodgroup, &hostname[0], 0,0)) {
910 (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
911 &hostname[0], goodgroup);
915 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
916 &hostname[0], goodgroup);
918 /* mark the entire netgroup as trusted */
919 (void)setnetgrent(goodgroup);
920 while (getnetgrent(&mach,&usr,&dom)) {
922 add_good_host(mach,0);
926 /* update list of slaves */
927 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
928 htp->good = good_host_name(&htp->name[0]);
934 /* see if a machine is trustworthy
936 int /* 1=trust hp to change our date */
940 register struct goodhost *ghp = goodhosts;
943 if (!ghp || !Mflag) /* trust everyone if no one named */
948 if (c == ghp->name[0]
949 && !strcasecmp(name, ghp->name))
950 return 1; /* found him, so say so */
951 } while (0 != (ghp = ghp->next));
953 if (!strcasecmp(name,hostname)) /* trust ourself */
956 return 0; /* did not find him */