timed.c revision 28547
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1985, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 351553Srgrimesstatic char copyright[] = 361553Srgrimes"@(#) Copyright (c) 1985, 1993\n\ 371553Srgrimes The Regents of the University of California. All rights reserved.\n"; 381553Srgrimes#endif /* not lint */ 391553Srgrimes 401553Srgrimes#ifndef lint 411553Srgrimesstatic char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93"; 421553Srgrimes#endif /* not lint */ 431553Srgrimes 441553Srgrimes#ifdef sgi 4528547Sjlemon#ident "$Revision: 1.3 $" 461553Srgrimes#endif /* sgi */ 471553Srgrimes 481553Srgrimes#define TSPTYPES 491553Srgrimes#include "globals.h" 501553Srgrimes#include <net/if.h> 511553Srgrimes#include <sys/file.h> 521553Srgrimes#include <sys/ioctl.h> 531553Srgrimes#include <setjmp.h> 541553Srgrimes#include "pathnames.h" 551553Srgrimes#include <math.h> 561553Srgrimes#include <sys/types.h> 571553Srgrimes#include <sys/times.h> 581553Srgrimes#ifdef sgi 591553Srgrimes#include <unistd.h> 601553Srgrimes#include <sys/syssgi.h> 611553Srgrimes#include <sys/schedctl.h> 621553Srgrimes#endif /* sgi */ 631553Srgrimes 641553Srgrimesint trace = 0; 651553Srgrimesint sock, sock_raw = -1; 661553Srgrimesint status = 0; 671553Srgrimesu_short sequence; /* sequence number */ 681553Srgrimeslong delay1; 691553Srgrimeslong delay2; 701553Srgrimes 711553Srgrimesint nslavenets; /* nets were I could be a slave */ 721553Srgrimesint nmasternets; /* nets were I could be a master */ 731553Srgrimesint nignorednets; /* ignored nets */ 741553Srgrimesint nnets; /* nets I am connected to */ 751553Srgrimes 761553SrgrimesFILE *fd; /* trace file FD */ 771553Srgrimes 781553Srgrimesjmp_buf jmpenv; 791553Srgrimes 801553Srgrimesstruct netinfo *nettab = 0; 811553Srgrimesstruct netinfo *slavenet; 821553Srgrimesint Mflag; 831553Srgrimesint justquit = 0; 841553Srgrimesint debug; 851553Srgrimes 861553Srgrimesstatic struct nets { 871553Srgrimes char *name; 881553Srgrimes long net; 891553Srgrimes struct nets *next; 901553Srgrimes} *nets = 0; 911553Srgrimes 921553Srgrimesstruct hosttbl hosttbl[NHOSTS+1]; /* known hosts */ 931553Srgrimes 941553Srgrimesstatic struct goodhost { /* hosts that we trust */ 951553Srgrimes char name[MAXHOSTNAMELEN+1]; 961553Srgrimes struct goodhost *next; 971553Srgrimes char perm; 981553Srgrimes} *goodhosts; 991553Srgrimes 1001553Srgrimesstatic char *goodgroup; /* net group of trusted hosts */ 1011553Srgrimesstatic void checkignorednets __P((void)); 1021553Srgrimesstatic void pickslavenet __P((struct netinfo *)); 1031553Srgrimesstatic void add_good_host __P((char *, int)); 1041553Srgrimes 1051553Srgrimes#ifdef sgi 1061553Srgrimeschar *timetrim_fn; 1071553Srgrimeschar *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n"; 1081553Srgrimeschar *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;"; 1091553Srgrimeslong timetrim; 1101553Srgrimesdouble tot_adj, hr_adj; /* totals in nsec */ 1111553Srgrimesdouble tot_ticks, hr_ticks; 1121553Srgrimes 1131553Srgrimesint bufspace = 60*1024; 1141553Srgrimes#endif 1151553Srgrimes 1161553Srgrimes 1171553Srgrimes/* 1181553Srgrimes * The timedaemons synchronize the clocks of hosts in a local area network. 1191553Srgrimes * One daemon runs as master, all the others as slaves. The master 1201553Srgrimes * performs the task of computing clock differences and sends correction 1211553Srgrimes * values to the slaves. 1221553Srgrimes * Slaves start an election to choose a new master when the latter disappears 1231553Srgrimes * because of a machine crash, network partition, or when killed. 1241553Srgrimes * A resolution protocol is used to kill all but one of the masters 1251553Srgrimes * that happen to exist in segments of a partitioned network when the 1261553Srgrimes * network partition is fixed. 1271553Srgrimes * 1281553Srgrimes * Authors: Riccardo Gusella & Stefano Zatti 1291553Srgrimes * 1301553Srgrimes * overhauled at Silicon Graphics 1311553Srgrimes */ 1321553Srgrimesint 1331553Srgrimesmain(argc, argv) 1341553Srgrimes int argc; 1351553Srgrimes char *argv[]; 1361553Srgrimes{ 1371553Srgrimes int on; 1381553Srgrimes int ret; 1391553Srgrimes int nflag, iflag; 1401553Srgrimes struct timeval ntime; 1411553Srgrimes struct servent *srvp; 1421553Srgrimes char buf[BUFSIZ], *cp, *cplim; 1431553Srgrimes struct ifconf ifc; 1441553Srgrimes struct ifreq ifreq, ifreqf, *ifr; 1451553Srgrimes register struct netinfo *ntp; 1461553Srgrimes struct netinfo *ntip; 1471553Srgrimes struct netinfo *savefromnet; 1481553Srgrimes struct netent *nentp; 1491553Srgrimes struct nets *nt; 1501553Srgrimes struct sockaddr_in server; 1511553Srgrimes u_short port; 1521553Srgrimes char c; 1531553Srgrimes extern char *optarg; 1541553Srgrimes extern int optind, opterr; 1551553Srgrimes#ifdef sgi 1561553Srgrimes FILE *timetrim_st; 1571553Srgrimes#endif 1581553Srgrimes 1591553Srgrimes#define IN_MSG "timed: -i and -n make no sense together\n" 1601553Srgrimes#ifdef sgi 1611553Srgrimes struct tms tms; 1621553Srgrimes#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp] [-P trimfile]\n" 1631553Srgrimes#else 1641553Srgrimes#ifdef HAVENIS 1651553Srgrimes#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n" 1661553Srgrimes#else 1671553Srgrimes#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...]\n" 1681553Srgrimes#endif /* HAVENIS */ 1691553Srgrimes#endif /* sgi */ 1701553Srgrimes 1711553Srgrimes#ifdef lint 1721553Srgrimes ntip = NULL; 1731553Srgrimes#endif 1741553Srgrimes 1751553Srgrimes on = 1; 1761553Srgrimes nflag = OFF; 1771553Srgrimes iflag = OFF; 1781553Srgrimes 1791553Srgrimes#ifdef sgi 1801553Srgrimes if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) { 1811553Srgrimes perror("timed: syssgi(GETTIMETRIM)"); 1821553Srgrimes timetrim = 0; 1831553Srgrimes } 1841553Srgrimes tot_ticks = hr_ticks = times(&tms); 1851553Srgrimes#endif /* sgi */ 1861553Srgrimes 1871553Srgrimes opterr = 0; 18824428Simp while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) { 1891553Srgrimes switch (c) { 1901553Srgrimes case 'M': 1911553Srgrimes Mflag = 1; 1921553Srgrimes break; 1931553Srgrimes 1941553Srgrimes case 't': 1951553Srgrimes trace = 1; 1961553Srgrimes break; 1971553Srgrimes 1981553Srgrimes case 'n': 1991553Srgrimes if (iflag) { 2001553Srgrimes fprintf(stderr, IN_MSG); 2011553Srgrimes exit(1); 2021553Srgrimes } else { 2031553Srgrimes nflag = ON; 2041553Srgrimes addnetname(optarg); 2051553Srgrimes } 2061553Srgrimes break; 2071553Srgrimes 2081553Srgrimes case 'i': 2091553Srgrimes if (nflag) { 2101553Srgrimes fprintf(stderr, IN_MSG); 2111553Srgrimes exit(1); 2121553Srgrimes } else { 2131553Srgrimes iflag = ON; 2141553Srgrimes addnetname(optarg); 2151553Srgrimes } 2161553Srgrimes break; 2171553Srgrimes 2181553Srgrimes case 'F': 2191553Srgrimes add_good_host(optarg,1); 2201553Srgrimes while (optind < argc && argv[optind][0] != '-') 2211553Srgrimes add_good_host(argv[optind++], 1); 2221553Srgrimes break; 2231553Srgrimes 2241553Srgrimes case 'd': 2251553Srgrimes debug = 1; 2261553Srgrimes break; 2271553Srgrimes case 'G': 2281553Srgrimes if (goodgroup != 0) { 2291553Srgrimes fprintf(stderr,"timed: only one net group\n"); 2301553Srgrimes exit(1); 2311553Srgrimes } 2321553Srgrimes goodgroup = optarg; 2331553Srgrimes break; 2341553Srgrimes#ifdef sgi 2351553Srgrimes case 'P': 2361553Srgrimes timetrim_fn = optarg; 2371553Srgrimes timetrim_st = fopen(timetrim_fn, "r+"); 2381553Srgrimes if (0 == timetrim_st) { 2391553Srgrimes if (errno != ENOENT) { 2401553Srgrimes (void)fprintf(stderr,"timed: "); 2411553Srgrimes perror(timetrim_fn); 2421553Srgrimes timetrim_fn = 0; 2431553Srgrimes } 2441553Srgrimes } else { 2451553Srgrimes int i; 2461553Srgrimes long trim; 2471553Srgrimes double adj, ticks; 2481553Srgrimes 2491553Srgrimes i = fscanf(timetrim_st, timetrim_rpat, 2501553Srgrimes &trim, &adj, &ticks); 2511553Srgrimes if (i < 1 2521553Srgrimes || trim > MAX_TRIM 2531553Srgrimes || trim < -MAX_TRIM 2541553Srgrimes || i == 2 2551553Srgrimes || (i == 3 2561553Srgrimes && trim != rint(adj*CLK_TCK/ticks))) { 2571553Srgrimes if (trace && i != EOF) 2581553Srgrimes (void)fprintf(stderr, 2591553Srgrimes "timed: unrecognized contents in %s\n", 2601553Srgrimes timetrim_fn); 2611553Srgrimes } else { 2621553Srgrimes if (0 > syssgi(SGI_SETTIMETRIM, 2631553Srgrimes trim)) { 2641553Srgrimes perror("timed: syssgi(SETTIMETRIM)"); 2651553Srgrimes } else { 2661553Srgrimes timetrim = trim; 2671553Srgrimes } 2681553Srgrimes if (i == 3) { 2691553Srgrimes tot_adj = adj; 2701553Srgrimes tot_ticks -= ticks; 2711553Srgrimes } 2721553Srgrimes } 2731553Srgrimes (void)fclose(timetrim_st); 2741553Srgrimes } 2751553Srgrimes break; 2761553Srgrimes#endif /* sgi */ 2771553Srgrimes 2781553Srgrimes default: 2791553Srgrimes fprintf(stderr, USAGE); 2801553Srgrimes exit(1); 2811553Srgrimes break; 2821553Srgrimes } 2831553Srgrimes } 2841553Srgrimes if (optind < argc) { 2851553Srgrimes fprintf(stderr, USAGE); 2861553Srgrimes exit(1); 2871553Srgrimes } 2881553Srgrimes 2891553Srgrimes /* If we care about which machine is the master, then we must 2901553Srgrimes * be willing to be a master 2911553Srgrimes */ 2921553Srgrimes if (0 != goodgroup || 0 != goodhosts) 2931553Srgrimes Mflag = 1; 2941553Srgrimes 2951553Srgrimes if (gethostname(hostname, sizeof(hostname) - 1) < 0) { 2961553Srgrimes perror("gethostname"); 2971553Srgrimes exit(1); 2981553Srgrimes } 2991553Srgrimes self.l_bak = &self; 3001553Srgrimes self.l_fwd = &self; 3011553Srgrimes self.h_bak = &self; 3021553Srgrimes self.h_fwd = &self; 3031553Srgrimes self.head = 1; 3041553Srgrimes self.good = 1; 3051553Srgrimes 3061553Srgrimes if (goodhosts != 0) /* trust ourself */ 3071553Srgrimes add_good_host(hostname,1); 3081553Srgrimes 3091553Srgrimes srvp = getservbyname("timed", "udp"); 3101553Srgrimes if (srvp == 0) { 3111553Srgrimes fprintf(stderr, "unknown service 'timed/udp'\n"); 3121553Srgrimes exit(1); 3131553Srgrimes } 3141553Srgrimes port = srvp->s_port; 3158532Sdg bzero(&server, sizeof(struct sockaddr_in)); 3161553Srgrimes server.sin_port = srvp->s_port; 3171553Srgrimes server.sin_family = AF_INET; 3181553Srgrimes sock = socket(AF_INET, SOCK_DGRAM, 0); 3191553Srgrimes if (sock < 0) { 3201553Srgrimes perror("socket"); 3211553Srgrimes exit(1); 3221553Srgrimes } 3231553Srgrimes if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, 3241553Srgrimes sizeof(on)) < 0) { 3251553Srgrimes perror("setsockopt"); 3261553Srgrimes exit(1); 3271553Srgrimes } 3281553Srgrimes if (bind(sock, (struct sockaddr*)&server, sizeof(server))) { 3291553Srgrimes if (errno == EADDRINUSE) 3301553Srgrimes fprintf(stderr,"timed: time daemon already running\n"); 3311553Srgrimes else 3321553Srgrimes perror("bind"); 3331553Srgrimes exit(1); 3341553Srgrimes } 3351553Srgrimes#ifdef sgi 3361553Srgrimes /* 3371553Srgrimes * handle many slaves with our buffer 3381553Srgrimes */ 3391553Srgrimes if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace, 3401553Srgrimes sizeof(bufspace))) { 3411553Srgrimes perror("setsockopt"); 3421553Srgrimes exit(1); 3431553Srgrimes } 3441553Srgrimes#endif /* sgi */ 3451553Srgrimes 3461553Srgrimes /* choose a unique seed for random number generation */ 3471553Srgrimes (void)gettimeofday(&ntime, 0); 3481553Srgrimes srandom(ntime.tv_sec + ntime.tv_usec); 3491553Srgrimes 3501553Srgrimes sequence = random(); /* initial seq number */ 3511553Srgrimes 3521553Srgrimes#ifndef sgi 3531553Srgrimes /* rounds kernel variable time to multiple of 5 ms. */ 3541553Srgrimes ntime.tv_sec = 0; 3551553Srgrimes ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000; 3561553Srgrimes (void)adjtime(&ntime, (struct timeval *)0); 3571553Srgrimes#endif /* sgi */ 3581553Srgrimes 3591553Srgrimes for (nt = nets; nt; nt = nt->next) { 3601553Srgrimes nentp = getnetbyname(nt->name); 3611553Srgrimes if (nentp == 0) { 3621553Srgrimes nt->net = inet_network(nt->name); 3631553Srgrimes if (nt->net != INADDR_NONE) 3641553Srgrimes nentp = getnetbyaddr(nt->net, AF_INET); 3651553Srgrimes } 3661553Srgrimes if (nentp != 0) { 3671553Srgrimes nt->net = nentp->n_net; 3681553Srgrimes } else if (nt->net == INADDR_NONE) { 3691553Srgrimes fprintf(stderr, "timed: unknown net %s\n", nt->name); 3701553Srgrimes exit(1); 3711553Srgrimes } else if (nt->net == INADDR_ANY) { 3721553Srgrimes fprintf(stderr, "timed: bad net %s\n", nt->name); 3731553Srgrimes exit(1); 3741553Srgrimes } else { 3751553Srgrimes fprintf(stderr, 3761553Srgrimes "timed: warning: %s unknown in /etc/networks\n", 3771553Srgrimes nt->name); 3781553Srgrimes } 3791553Srgrimes 3801553Srgrimes if (0 == (nt->net & 0xff000000)) 3811553Srgrimes nt->net <<= 8; 3821553Srgrimes if (0 == (nt->net & 0xff000000)) 3831553Srgrimes nt->net <<= 8; 3841553Srgrimes if (0 == (nt->net & 0xff000000)) 3851553Srgrimes nt->net <<= 8; 3861553Srgrimes } 3871553Srgrimes ifc.ifc_len = sizeof(buf); 3881553Srgrimes ifc.ifc_buf = buf; 3891553Srgrimes if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 3901553Srgrimes perror("timed: get interface configuration"); 3911553Srgrimes exit(1); 3921553Srgrimes } 3931553Srgrimes ntp = NULL; 3941553Srgrimes#ifdef sgi 3951553Srgrimes#define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */ 3961553Srgrimes#else 3971553Srgrimes#define size(p) max((p).sa_len, sizeof(p)) 3981553Srgrimes#endif 3991553Srgrimes cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ 4001553Srgrimes for (cp = buf; cp < cplim; 4011553Srgrimes cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { 4021553Srgrimes ifr = (struct ifreq *)cp; 4031553Srgrimes if (ifr->ifr_addr.sa_family != AF_INET) 4041553Srgrimes continue; 4051553Srgrimes if (!ntp) 4061553Srgrimes ntp = (struct netinfo*)malloc(sizeof(struct netinfo)); 4071553Srgrimes bzero(ntp,sizeof(*ntp)); 4081553Srgrimes ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; 4091553Srgrimes ntp->status = NOMASTER; 4101553Srgrimes ifreq = *ifr; 4111553Srgrimes ifreqf = *ifr; 4121553Srgrimes 4131553Srgrimes if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) { 4141553Srgrimes perror("get interface flags"); 4151553Srgrimes continue; 4161553Srgrimes } 4171553Srgrimes if ((ifreqf.ifr_flags & IFF_UP) == 0) 4181553Srgrimes continue; 4191553Srgrimes if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 && 4201553Srgrimes (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) { 4211553Srgrimes continue; 4221553Srgrimes } 4231553Srgrimes 4241553Srgrimes 4251553Srgrimes if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 4261553Srgrimes perror("get netmask"); 4271553Srgrimes continue; 4281553Srgrimes } 4291553Srgrimes ntp->mask = ((struct sockaddr_in *) 4301553Srgrimes &ifreq.ifr_addr)->sin_addr.s_addr; 4311553Srgrimes 4321553Srgrimes if (ifreqf.ifr_flags & IFF_BROADCAST) { 4331553Srgrimes if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 4341553Srgrimes perror("get broadaddr"); 4351553Srgrimes continue; 4361553Srgrimes } 4371553Srgrimes ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr; 4381553Srgrimes /* What if the broadcast address is all ones? 4391553Srgrimes * So we cannot just mask ntp->dest_addr. */ 4401553Srgrimes ntp->net = ntp->my_addr; 4411553Srgrimes ntp->net.s_addr &= ntp->mask; 4421553Srgrimes } else { 4431553Srgrimes if (ioctl(sock, SIOCGIFDSTADDR, 4441553Srgrimes (char *)&ifreq) < 0) { 4451553Srgrimes perror("get destaddr"); 4461553Srgrimes continue; 4471553Srgrimes } 4481553Srgrimes ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr; 4491553Srgrimes ntp->net = ntp->dest_addr.sin_addr; 4501553Srgrimes } 4511553Srgrimes 4521553Srgrimes ntp->dest_addr.sin_port = port; 4531553Srgrimes 4541553Srgrimes for (nt = nets; nt; nt = nt->next) { 45528547Sjlemon if (ntp->net.s_addr == htonl(nt->net)) 4561553Srgrimes break; 4571553Srgrimes } 4581553Srgrimes if (nflag && !nt || iflag && nt) 4591553Srgrimes continue; 4601553Srgrimes 4611553Srgrimes ntp->next = NULL; 4621553Srgrimes if (nettab == NULL) { 4631553Srgrimes nettab = ntp; 4641553Srgrimes } else { 4651553Srgrimes ntip->next = ntp; 4661553Srgrimes } 4671553Srgrimes ntip = ntp; 4681553Srgrimes ntp = NULL; 4691553Srgrimes } 4701553Srgrimes if (ntp) 4711553Srgrimes (void) free((char *)ntp); 4721553Srgrimes if (nettab == NULL) { 4731553Srgrimes fprintf(stderr, "timed: no network usable\n"); 4741553Srgrimes exit(1); 4751553Srgrimes } 4761553Srgrimes 4771553Srgrimes 4781553Srgrimes#ifdef sgi 4791553Srgrimes (void)schedctl(RENICE,0,10); /* run fast to get good time */ 4801553Srgrimes 4811553Srgrimes /* ticks to delay before responding to a broadcast */ 4821553Srgrimes delay1 = casual(0, CLK_TCK/10); 4831553Srgrimes#else 4841553Srgrimes 4851553Srgrimes /* microseconds to delay before responding to a broadcast */ 4861553Srgrimes delay1 = casual(1, 100*1000); 4871553Srgrimes#endif /* sgi */ 4881553Srgrimes 4891553Srgrimes /* election timer delay in secs. */ 4901553Srgrimes delay2 = casual(MINTOUT, MAXTOUT); 4911553Srgrimes 4921553Srgrimes 4931553Srgrimes#ifdef sgi 4941553Srgrimes (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1); 4951553Srgrimes#else 4961553Srgrimes if (!debug) 4971553Srgrimes daemon(debug, 0); 4981553Srgrimes#endif /* sgi */ 4991553Srgrimes 5001553Srgrimes if (trace) 5011553Srgrimes traceon(); 5021553Srgrimes openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON); 5031553Srgrimes 5041553Srgrimes /* 5051553Srgrimes * keep returning here 5061553Srgrimes */ 5071553Srgrimes ret = setjmp(jmpenv); 5081553Srgrimes savefromnet = fromnet; 5091553Srgrimes setstatus(); 5101553Srgrimes 5111553Srgrimes if (Mflag) { 5121553Srgrimes switch (ret) { 5131553Srgrimes 5141553Srgrimes case 0: 5151553Srgrimes checkignorednets(); 5161553Srgrimes pickslavenet(0); 5171553Srgrimes break; 5181553Srgrimes case 1: 5191553Srgrimes /* Just lost our master */ 5201553Srgrimes if (slavenet != 0) 5211553Srgrimes slavenet->status = election(slavenet); 5221553Srgrimes if (!slavenet || slavenet->status == MASTER) { 5231553Srgrimes checkignorednets(); 5241553Srgrimes pickslavenet(0); 5251553Srgrimes } else { 5261553Srgrimes makeslave(slavenet); /* prune extras */ 5271553Srgrimes } 5281553Srgrimes break; 5291553Srgrimes 5301553Srgrimes case 2: 5311553Srgrimes /* Just been told to quit */ 5321553Srgrimes justquit = 1; 5331553Srgrimes pickslavenet(savefromnet); 5341553Srgrimes break; 5351553Srgrimes } 5361553Srgrimes 5371553Srgrimes setstatus(); 5381553Srgrimes if (!(status & MASTER) && sock_raw != -1) { 5391553Srgrimes /* sock_raw is not being used now */ 5401553Srgrimes (void)close(sock_raw); 5411553Srgrimes sock_raw = -1; 5421553Srgrimes } 5431553Srgrimes 5441553Srgrimes if (status == MASTER) 5451553Srgrimes master(); 5461553Srgrimes else 5471553Srgrimes slave(); 5481553Srgrimes 5491553Srgrimes } else { 5501553Srgrimes if (sock_raw != -1) { 5511553Srgrimes (void)close(sock_raw); 5521553Srgrimes sock_raw = -1; 5531553Srgrimes } 5541553Srgrimes 5551553Srgrimes if (ret) { 5561553Srgrimes /* we just lost our master or were told to quit */ 5571553Srgrimes justquit = 1; 5581553Srgrimes } 5591553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 5601553Srgrimes if (ntp->status == MASTER) 5611553Srgrimes rmnetmachs(ntp); 5621553Srgrimes ntp->status = NOMASTER; 5631553Srgrimes } 5641553Srgrimes checkignorednets(); 5651553Srgrimes pickslavenet(0); 5661553Srgrimes setstatus(); 5671553Srgrimes 5681553Srgrimes slave(); 5691553Srgrimes } 5701553Srgrimes /* NOTREACHED */ 5711553Srgrimes#ifdef lint 5721553Srgrimes return(0); 5731553Srgrimes#endif 5741553Srgrimes} 5751553Srgrimes 5761553Srgrimes/* 5771553Srgrimes * suppress an upstart, untrustworthy, self-appointed master 5781553Srgrimes */ 5791553Srgrimesvoid 5801553Srgrimessuppress(addr, name,net) 5811553Srgrimes struct sockaddr_in *addr; 5821553Srgrimes char *name; 5831553Srgrimes struct netinfo *net; 5841553Srgrimes{ 5851553Srgrimes struct sockaddr_in tgt; 5861553Srgrimes char tname[MAXHOSTNAMELEN]; 5871553Srgrimes struct tsp msg; 5881553Srgrimes static struct timeval wait; 5891553Srgrimes 5901553Srgrimes if (trace) 5911553Srgrimes fprintf(fd, "suppress: %s\n", name); 5921553Srgrimes tgt = *addr; 5931553Srgrimes (void)strcpy(tname, name); 5941553Srgrimes 5951553Srgrimes while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) { 5961553Srgrimes if (trace) 5971553Srgrimes fprintf(fd, "suppress:\tdiscarded packet from %s\n", 5981553Srgrimes name); 5991553Srgrimes } 6001553Srgrimes 6011553Srgrimes syslog(LOG_NOTICE, "suppressing false master %s", tname); 6021553Srgrimes msg.tsp_type = TSP_QUIT; 6031553Srgrimes (void)strcpy(msg.tsp_name, hostname); 6041553Srgrimes (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1); 6051553Srgrimes} 6061553Srgrimes 6071553Srgrimesvoid 6081553Srgrimeslookformaster(ntp) 6091553Srgrimes struct netinfo *ntp; 6101553Srgrimes{ 6111553Srgrimes struct tsp resp, conflict, *answer; 6121553Srgrimes struct timeval ntime; 6131553Srgrimes char mastername[MAXHOSTNAMELEN]; 6141553Srgrimes struct sockaddr_in masteraddr; 6151553Srgrimes 6161553Srgrimes get_goodgroup(0); 6171553Srgrimes ntp->status = SLAVE; 6181553Srgrimes 6191553Srgrimes /* look for master */ 6201553Srgrimes resp.tsp_type = TSP_MASTERREQ; 6211553Srgrimes (void)strcpy(resp.tsp_name, hostname); 6221553Srgrimes answer = acksend(&resp, &ntp->dest_addr, ANYADDR, 6231553Srgrimes TSP_MASTERACK, ntp, 0); 6241553Srgrimes if (answer != 0 && !good_host_name(answer->tsp_name)) { 6251553Srgrimes suppress(&from, answer->tsp_name, ntp); 6261553Srgrimes ntp->status = NOMASTER; 6271553Srgrimes answer = 0; 6281553Srgrimes } 6291553Srgrimes if (answer == 0) { 6301553Srgrimes /* 6311553Srgrimes * Various conditions can cause conflict: races between 6321553Srgrimes * two just started timedaemons when no master is 6331553Srgrimes * present, or timedaemons started during an election. 6341553Srgrimes * A conservative approach is taken. Give up and became a 6351553Srgrimes * slave, postponing election of a master until first 6361553Srgrimes * timer expires. 6371553Srgrimes */ 6381553Srgrimes ntime.tv_sec = ntime.tv_usec = 0; 6391553Srgrimes answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp); 6401553Srgrimes if (answer != 0) { 6411553Srgrimes if (!good_host_name(answer->tsp_name)) { 6421553Srgrimes suppress(&from, answer->tsp_name, ntp); 6431553Srgrimes ntp->status = NOMASTER; 6441553Srgrimes } 6451553Srgrimes return; 6461553Srgrimes } 6471553Srgrimes 6481553Srgrimes ntime.tv_sec = ntime.tv_usec = 0; 6491553Srgrimes answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp); 6501553Srgrimes if (answer != 0) { 6511553Srgrimes if (!good_host_name(answer->tsp_name)) { 6521553Srgrimes suppress(&from, answer->tsp_name, ntp); 6531553Srgrimes ntp->status = NOMASTER; 6541553Srgrimes } 6551553Srgrimes return; 6561553Srgrimes } 6571553Srgrimes 6581553Srgrimes ntime.tv_sec = ntime.tv_usec = 0; 6591553Srgrimes answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp); 6601553Srgrimes if (answer != 0) { 6611553Srgrimes if (!good_host_name(answer->tsp_name)) { 6621553Srgrimes suppress(&from, answer->tsp_name, ntp); 6631553Srgrimes ntp->status = NOMASTER; 6641553Srgrimes } 6651553Srgrimes return; 6661553Srgrimes } 6671553Srgrimes 6681553Srgrimes if (Mflag) 6691553Srgrimes ntp->status = MASTER; 6701553Srgrimes else 6711553Srgrimes ntp->status = NOMASTER; 6721553Srgrimes return; 6731553Srgrimes } 6741553Srgrimes 6751553Srgrimes ntp->status = SLAVE; 6761553Srgrimes (void)strcpy(mastername, answer->tsp_name); 6771553Srgrimes masteraddr = from; 6781553Srgrimes 6791553Srgrimes /* 6801553Srgrimes * If network has been partitioned, there might be other 6811553Srgrimes * masters; tell the one we have just acknowledged that 6821553Srgrimes * it has to gain control over the others. 6831553Srgrimes */ 6841553Srgrimes ntime.tv_sec = 0; 6851553Srgrimes ntime.tv_usec = 300000; 6861553Srgrimes answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp); 6871553Srgrimes /* 6881553Srgrimes * checking also not to send CONFLICT to ack'ed master 6891553Srgrimes * due to duplicated MASTERACKs 6901553Srgrimes */ 6911553Srgrimes if (answer != NULL && 6921553Srgrimes strcmp(answer->tsp_name, mastername) != 0) { 6931553Srgrimes conflict.tsp_type = TSP_CONFLICT; 6941553Srgrimes (void)strcpy(conflict.tsp_name, hostname); 6951553Srgrimes if (!acksend(&conflict, &masteraddr, mastername, 6961553Srgrimes TSP_ACK, 0, 0)) { 6971553Srgrimes syslog(LOG_ERR, 6981553Srgrimes "error on sending TSP_CONFLICT"); 6991553Srgrimes } 7001553Srgrimes } 7011553Srgrimes} 7021553Srgrimes 7031553Srgrimes/* 7041553Srgrimes * based on the current network configuration, set the status, and count 7051553Srgrimes * networks; 7061553Srgrimes */ 7071553Srgrimesvoid 7081553Srgrimessetstatus() 7091553Srgrimes{ 7101553Srgrimes struct netinfo *ntp; 7111553Srgrimes 7121553Srgrimes status = 0; 7131553Srgrimes nmasternets = nslavenets = nnets = nignorednets = 0; 7141553Srgrimes if (trace) 7151553Srgrimes fprintf(fd, "Net status:\n"); 7161553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 7171553Srgrimes switch ((int)ntp->status) { 7181553Srgrimes case MASTER: 7191553Srgrimes nmasternets++; 7201553Srgrimes break; 7211553Srgrimes case SLAVE: 7221553Srgrimes nslavenets++; 7231553Srgrimes break; 7241553Srgrimes case NOMASTER: 7251553Srgrimes case IGNORE: 7261553Srgrimes nignorednets++; 7271553Srgrimes break; 7281553Srgrimes } 7291553Srgrimes if (trace) { 7301553Srgrimes fprintf(fd, "\t%-16s", inet_ntoa(ntp->net)); 7311553Srgrimes switch ((int)ntp->status) { 7321553Srgrimes case NOMASTER: 7331553Srgrimes fprintf(fd, "NOMASTER\n"); 7341553Srgrimes break; 7351553Srgrimes case MASTER: 7361553Srgrimes fprintf(fd, "MASTER\n"); 7371553Srgrimes break; 7381553Srgrimes case SLAVE: 7391553Srgrimes fprintf(fd, "SLAVE\n"); 7401553Srgrimes break; 7411553Srgrimes case IGNORE: 7421553Srgrimes fprintf(fd, "IGNORE\n"); 7431553Srgrimes break; 7441553Srgrimes default: 7451553Srgrimes fprintf(fd, "invalid state %d\n", 7461553Srgrimes (int)ntp->status); 7471553Srgrimes break; 7481553Srgrimes } 7491553Srgrimes } 7501553Srgrimes nnets++; 7511553Srgrimes status |= ntp->status; 7521553Srgrimes } 7531553Srgrimes status &= ~IGNORE; 7541553Srgrimes if (trace) 7551553Srgrimes fprintf(fd, 7561553Srgrimes "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%d\n", 7571553Srgrimes nnets, nmasternets, nslavenets, nignorednets, delay2); 7581553Srgrimes} 7591553Srgrimes 7601553Srgrimesvoid 7611553Srgrimesmakeslave(net) 7621553Srgrimes struct netinfo *net; 7631553Srgrimes{ 7641553Srgrimes register struct netinfo *ntp; 7651553Srgrimes 7661553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 7671553Srgrimes if (ntp->status == SLAVE && ntp != net) 7681553Srgrimes ntp->status = IGNORE; 7691553Srgrimes } 7701553Srgrimes slavenet = net; 7711553Srgrimes} 7721553Srgrimes 7731553Srgrimes/* 7741553Srgrimes * Try to become master over ignored nets.. 7751553Srgrimes */ 7761553Srgrimesstatic void 7771553Srgrimescheckignorednets() 7781553Srgrimes{ 7791553Srgrimes register struct netinfo *ntp; 7801553Srgrimes 7811553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 7821553Srgrimes if (!Mflag && ntp->status == SLAVE) 7831553Srgrimes break; 7841553Srgrimes 7851553Srgrimes if (ntp->status == IGNORE || ntp->status == NOMASTER) { 7861553Srgrimes lookformaster(ntp); 7871553Srgrimes if (!Mflag && ntp->status == SLAVE) 7881553Srgrimes break; 7891553Srgrimes } 7901553Srgrimes } 7911553Srgrimes} 7921553Srgrimes 7931553Srgrimes/* 7941553Srgrimes * choose a good network on which to be a slave 7951553Srgrimes * The ignored networks must have already been checked. 7961553Srgrimes * Take a hint about for a good network. 7971553Srgrimes */ 7981553Srgrimesstatic void 7991553Srgrimespickslavenet(ntp) 8001553Srgrimes struct netinfo *ntp; 8011553Srgrimes{ 8021553Srgrimes if (slavenet != 0 && slavenet->status == SLAVE) { 8031553Srgrimes makeslave(slavenet); /* prune extras */ 8041553Srgrimes return; 8051553Srgrimes } 8061553Srgrimes 8071553Srgrimes if (ntp == 0 || ntp->status != SLAVE) { 8081553Srgrimes for (ntp = nettab; ntp != 0; ntp = ntp->next) { 8091553Srgrimes if (ntp->status == SLAVE) 8101553Srgrimes break; 8111553Srgrimes } 8121553Srgrimes } 8131553Srgrimes makeslave(ntp); 8141553Srgrimes} 8151553Srgrimes 8161553Srgrimes/* 8171553Srgrimes * returns a random number in the range [inf, sup] 8181553Srgrimes */ 8191553Srgrimeslong 8201553Srgrimescasual(inf, sup) 8211553Srgrimes long inf, sup; 8221553Srgrimes{ 8231553Srgrimes double value; 8241553Srgrimes 8251553Srgrimes value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0); 8261553Srgrimes return(inf + (sup - inf)*value); 8271553Srgrimes} 8281553Srgrimes 8291553Srgrimeschar * 8301553Srgrimesdate() 8311553Srgrimes{ 8321553Srgrimes#ifdef sgi 8331553Srgrimes struct timeval tv; 8341553Srgrimes static char tm[32]; 8351553Srgrimes 8361553Srgrimes (void)gettimeofday(&tv, (struct timezone *)0); 8371553Srgrimes (void)cftime(tm, "%D %T", &tv.tv_sec); 8381553Srgrimes return (tm); 8391553Srgrimes#else 8401553Srgrimes struct timeval tv; 8411553Srgrimes 8421553Srgrimes (void)gettimeofday(&tv, (struct timezone *)0); 8431553Srgrimes return (ctime(&tv.tv_sec)); 8441553Srgrimes#endif /* sgi */ 8451553Srgrimes} 8461553Srgrimes 8471553Srgrimesvoid 8481553Srgrimesaddnetname(name) 8491553Srgrimes char *name; 8501553Srgrimes{ 8511553Srgrimes register struct nets **netlist = &nets; 8521553Srgrimes 8531553Srgrimes while (*netlist) 8541553Srgrimes netlist = &((*netlist)->next); 8551553Srgrimes *netlist = (struct nets *)malloc(sizeof **netlist); 8561553Srgrimes if (*netlist == 0) { 8571553Srgrimes fprintf(stderr,"malloc failed\n"); 8581553Srgrimes exit(1); 8591553Srgrimes } 8601553Srgrimes bzero((char *)*netlist, sizeof(**netlist)); 8611553Srgrimes (*netlist)->name = name; 8621553Srgrimes} 8631553Srgrimes 8641553Srgrimes/* note a host as trustworthy */ 8651553Srgrimesstatic void 8661553Srgrimesadd_good_host(name, perm) 8671553Srgrimes char *name; 8681553Srgrimes int perm; /* 1=not part of the netgroup */ 8691553Srgrimes{ 8701553Srgrimes register struct goodhost *ghp; 8711553Srgrimes register struct hostent *hentp; 8721553Srgrimes 8731553Srgrimes ghp = (struct goodhost*)malloc(sizeof(*ghp)); 8741553Srgrimes if (!ghp) { 8751553Srgrimes syslog(LOG_ERR, "malloc failed"); 8761553Srgrimes exit(1); 8771553Srgrimes } 8781553Srgrimes 8791553Srgrimes bzero((char*)ghp, sizeof(*ghp)); 8801553Srgrimes (void)strncpy(&ghp->name[0], name, sizeof(ghp->name)); 8811553Srgrimes ghp->next = goodhosts; 8821553Srgrimes ghp->perm = perm; 8831553Srgrimes goodhosts = ghp; 8841553Srgrimes 8851553Srgrimes hentp = gethostbyname(name); 8861553Srgrimes if (0 == hentp && perm) 8871553Srgrimes (void)fprintf(stderr, "unknown host %s\n", name); 8881553Srgrimes} 8891553Srgrimes 8901553Srgrimes 8911553Srgrimes/* update our image of the net-group of trustworthy hosts 8921553Srgrimes */ 8931553Srgrimesvoid 8941553Srgrimesget_goodgroup(force) 8951553Srgrimes int force; 8961553Srgrimes{ 8971553Srgrimes# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ 8981553Srgrimes static unsigned long last_update = -NG_DELAY; 8991553Srgrimes unsigned long new_update; 9001553Srgrimes struct hosttbl *htp; 9011553Srgrimes struct goodhost *ghp, **ghpp; 9021553Srgrimes char *mach, *usr, *dom; 9031553Srgrimes struct tms tm; 9041553Srgrimes 9051553Srgrimes 9061553Srgrimes /* if no netgroup, then we are finished */ 9071553Srgrimes if (goodgroup == 0 || !Mflag) 9081553Srgrimes return; 9091553Srgrimes 9101553Srgrimes /* Do not chatter with the netgroup master too often. 9111553Srgrimes */ 9121553Srgrimes new_update = times(&tm); 9131553Srgrimes if (new_update < last_update + NG_DELAY 9141553Srgrimes && !force) 9151553Srgrimes return; 9161553Srgrimes last_update = new_update; 9171553Srgrimes 9181553Srgrimes /* forget the old temporary entries */ 9191553Srgrimes ghpp = &goodhosts; 9201553Srgrimes while (0 != (ghp = *ghpp)) { 9211553Srgrimes if (!ghp->perm) { 9221553Srgrimes *ghpp = ghp->next; 9231553Srgrimes free((char*)ghp); 9241553Srgrimes } else { 9251553Srgrimes ghpp = &ghp->next; 9261553Srgrimes } 9271553Srgrimes } 9281553Srgrimes 9291553Srgrimes#ifdef HAVENIS 9301553Srgrimes /* quit now if we are not one of the trusted masters 9311553Srgrimes */ 9321553Srgrimes if (!innetgr(goodgroup, &hostname[0], 0,0)) { 9331553Srgrimes if (trace) 9341553Srgrimes (void)fprintf(fd, "get_goodgroup: %s not in %s\n", 9351553Srgrimes &hostname[0], goodgroup); 9361553Srgrimes return; 9371553Srgrimes } 9381553Srgrimes if (trace) 9391553Srgrimes (void)fprintf(fd, "get_goodgroup: %s in %s\n", 9401553Srgrimes &hostname[0], goodgroup); 9411553Srgrimes 9421553Srgrimes /* mark the entire netgroup as trusted */ 9431553Srgrimes (void)setnetgrent(goodgroup); 9441553Srgrimes while (getnetgrent(&mach,&usr,&dom)) { 9451553Srgrimes if (0 != mach) 9461553Srgrimes add_good_host(mach,0); 9471553Srgrimes } 9481553Srgrimes (void)endnetgrent(); 9491553Srgrimes 9501553Srgrimes /* update list of slaves */ 9511553Srgrimes for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 9521553Srgrimes htp->good = good_host_name(&htp->name[0]); 9531553Srgrimes } 9541553Srgrimes#endif /* HAVENIS */ 9551553Srgrimes} 9561553Srgrimes 9571553Srgrimes 9581553Srgrimes/* see if a machine is trustworthy 9591553Srgrimes */ 9601553Srgrimesint /* 1=trust hp to change our date */ 9611553Srgrimesgood_host_name(name) 9621553Srgrimes char *name; 9631553Srgrimes{ 9641553Srgrimes register struct goodhost *ghp = goodhosts; 9651553Srgrimes register char c; 9661553Srgrimes 9671553Srgrimes if (!ghp || !Mflag) /* trust everyone if no one named */ 9681553Srgrimes return 1; 9691553Srgrimes 9701553Srgrimes c = *name; 9711553Srgrimes do { 9721553Srgrimes if (c == ghp->name[0] 9731553Srgrimes && !strcasecmp(name, ghp->name)) 9741553Srgrimes return 1; /* found him, so say so */ 9751553Srgrimes } while (0 != (ghp = ghp->next)); 9761553Srgrimes 9771553Srgrimes if (!strcasecmp(name,hostname)) /* trust ourself */ 9781553Srgrimes return 1; 9791553Srgrimes 9801553Srgrimes return 0; /* did not find him */ 9811553Srgrimes} 982