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