Ultrix-3.1/src/etc/rdate.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

#ifndef lint
static	char	*sccsid = "@(#)rdate.c	3.0	(ULTRIX-11)	4/22/86";
#endif lint

/*-----------------------------------------------------------------------
 *	Modification History
 *
 *	4/5/85 -- jrs
 *		Created to allow machines to set time from network.
 *		Based on a concept by Marshall Rose of UC Irvine
 *		and the internet specifications for time server.
 *
 *-----------------------------------------------------------------------
 */

/*
 *	The syntax for this client is:
 *	rdate [-sv] [network]
 *
 *	where: 
 *		-s	Set time from network median
 *		-v	Print time for each responding network host
 *		network	The network is poll for time
 *
 *	If no switches are set, rdate will just report the network median time
 *	If no network is specified, rdate will use the host's primary network.
 *
 *	It is intended that rdate will normally be used in the /etc/rc file
 *	with the -s switch to set the system date.  This is especially useful
 *	on machines such as MicroVax I's that have no t.o.y. clock.
 */

#include <netdb.h>
#include <stdio.h>
#include <utmp.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#ifndef	pdp11
#include <sys/time.h>
#endif	pdp11
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/if.h>

#define	WTMP	"/usr/adm/wtmp"
#define	RESMAX	100

struct	utmp wtmp[2] = { { "|", "", "", 0 }, { "{", "", "", 0 } };

struct	servent *getservbyname();
struct	netent *getnetbyname();
struct	hostent *gethostbyname();
#ifndef	pdp11
struct	in_addr inet_makeaddr();
#else	pdp11
struct	in_addr inet_mkaddr();
#endif	pdp11
int	tcomp();

main(argc, argv)
int	argc;
char	**argv;
{
	int	set = 0;
	int	verbose = 0;
	char	*net = NULL;
	int on = 1;
	struct	servent	*tserv;
	struct	netent	*tnet;
	struct	hostent	*thost;
	struct	sockaddr_in netaddr;
#ifndef	pdp11
	struct	timeval baset, nowt, timeout;
	struct	timezone basez, nowz;
#else	pdp11
	long	baset, nowt;
	int	timeout;
#endif	pdp11
	char	hostnam[32], resbuf[16], *swtp;
#ifndef	pdp11
	int	argp, wtmpfd, tsock, readsel, writesel, selmax, selvalue;
#else	pdp11
	int	argp, wtmpfd, tsock, selmax, selvalue;
	long	readsel, writesel;
#endif	pdp11
	int	rescount, median, addrsiz;
#ifndef	pdp11
	unsigned long reslist[RESMAX], resvalue;
#else	pdp11
	long reslist[RESMAX], resvalue;
#endif	pdp11
	struct ifreq ifreq;

	for (argp = 1; argp < argc; argp++) {
		if (*argv[argp] == '-') {
			for (swtp = &argv[argp][1]; *swtp != '\0'; swtp++) {
				switch (*swtp) {

				case 's':	/* set time */
					set = 1;
					break;

				case 'v':	/* verbose report */
					verbose = 1;
					break;

				default:
					fprintf(stderr,
						"%s: Unknown switch - %c\n",
						argv[0], *swtp);
					exit(1);
				}
			}
		} else {
			net = argv[argp];
		}
	}

	/* set up the socket and define the base time */

	if ((tsock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		fprintf(stderr, "%s: socket create failure\n", argv[0]);
		exit(1);
	}
	if (setsockopt(tsock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
		fprintf(stderr, "%s: set broadcast failure\n", argv[0]);
		exit(1);
	}

	/* research network and service information */

	if ((tserv = getservbyname("time", "udp")) == NULL) {
		fprintf(stderr, "%s: Time service unknown\n", argv[0]);
		exit(1);
	}
	netaddr.sin_family = AF_INET;
	netaddr.sin_port = tserv->s_port;
	if (net == NULL) {
		(void) gethostname(hostnam, sizeof(hostnam));
		if ((thost = gethostbyname(hostnam)) == NULL) {
			fprintf(stderr, "%s: Host name not known\n", argv[0]);
			exit(1);
		}
		/* next line is for subnets */
		netaddr.sin_addr = inet_makeaddr(inet_netof(
				*(struct in_addr *)thost->h_addr), INADDR_ANY);

	} else {
		if ((tnet = getnetbyname(net)) == NULL) {
			fprintf(stderr, "%s: Unknown network - %s\n",
					argv[0], net);
		}
		(void) strncpy(&netaddr.sin_addr, &tnet->n_net, sizeof(struct in_addr));
	}

#ifndef	pdp11
	(void) gettimeofday(&baset, &basez);
#else	pdp11
	time(&baset);
#endif	pdp11

	/* set up for select, then yell for someone to tell us the time */

#ifndef	pdp11
	timeout.tv_sec = 2;
	timeout.tv_usec = 0;
	readsel = 1 << tsock;
#else	pdp11
	timeout = 2;
	readsel = 1L << tsock;
#endif	pdp11
	writesel = 0;
	selmax = tsock + 1;
	rescount = 0;

	if (sendto(tsock, resbuf, sizeof(resbuf), 0, &netaddr,
				sizeof(netaddr)) < 0) {
		fprintf(stderr, "%s: socket send failure\n", argv[0]);
		exit(1);
	}

	/* loop for incoming packets.  We will break out on error
	   or timeout period expiration */

#ifndef	pdp11
	while ((selvalue = select(selmax, &readsel, &writesel, &writesel,
				&timeout)) > 0) {
#else	pdp11
	while ((selvalue = select(selmax, &readsel, 0, 0, &timeout)) > 0) {
#endif	pdp11

		/* reset for next select */

#ifndef	pdp11
		timeout.tv_sec = 2;
		timeout.tv_usec = 0;
		readsel = 1 << tsock;
#else	pdp11
		timeout = 2;
		readsel = 1L << tsock;
#endif	pdp11
		writesel = 0;
		selmax = tsock + 1;
		
		/* try to pick up packet */

		addrsiz = sizeof(netaddr);
		if (recvfrom(tsock, resbuf, sizeof(resbuf), 0, &netaddr,
				&addrsiz) != sizeof(resvalue)) {
			continue;
		}
		
		/* this little piece of code is to insure that all
		   incoming times are stamped from same base time */

#ifndef	pdp11
		(void) gettimeofday(&nowt, &nowz);
		resvalue = ntohl(*(unsigned long *)resbuf) - 2208988800l;
		reslist[rescount++] = resvalue - (nowt.tv_sec - baset.tv_sec);
#else	pdp11
		time(&nowt);
		resvalue = ntohl(*(long *)resbuf) - 2208988800L;
		reslist[rescount++] = resvalue - (nowt - baset);
#endif	pdp11

		/* if we are verbose, explain what we just got */

		if (verbose != 0) {
			thost = gethostbyaddr(&netaddr.sin_addr,
					sizeof(netaddr.sin_addr), AF_INET);
			printf("%s: %s", (thost == NULL)? "*Unknown*":
					thost->h_name, ctime(&resvalue));
		}

		/* if list is full, we are done */

		if (rescount >= RESMAX) {
			selvalue = 0;
			break;
		}
	}

	/* make sure we did not end abnormally */

	if (selvalue != 0) {
		fprintf(stderr, "%s: select failure\n", argv[0]);
		exit(1);
	}

	/* cheap exit if time list is empty */

	if (rescount == 0) {
		printf("Network time indeterminate\n");
		exit(0);
	}

	/* sort the time list and pick median */

	qsort(reslist, rescount, sizeof(resvalue), tcomp);
	median = (rescount - 1) / 2;

	/* adjust selected value from base time to present */

#ifndef	pdp11
	(void) gettimeofday(&nowt, &nowz);
	resvalue = reslist[median] + (nowt.tv_sec - baset.tv_sec);
#else	pdp11
	time(&nowt);
	resvalue = reslist[median] + (nowt - baset);
#endif	pdp11

	/* if setting, do it, otherwise just print conclusions */

	if (set == 0) {
		fprintf(stderr, "Network time is %s", ctime(&resvalue));
	} else {
#ifndef	pdp11
		wtmp[0].ut_time = nowt.tv_sec;
		wtmp[1].ut_time = resvalue;
		nowt.tv_sec = resvalue;
		if (settimeofday(&nowt, &nowz) != 0) {
			fprintf(stderr, "%s: Time set failed\n", argv[0]);
			exit(1);
		}
#else	pdp11
		wtmp[0].ut_time = nowt;
		wtmp[1].ut_time = resvalue;
		nowt = resvalue;
		if (stime(&nowt) != 0) {
			fprintf(stderr, "%s: Time set failed\n", argv[0]);
			exit(1);
		}
#endif	pdp11
		if ((wtmpfd = open(WTMP, O_WRONLY|O_APPEND)) >= 0) {
			(void) write(wtmpfd, wtmp, sizeof(wtmp));
			(void) close(wtmpfd);
		}
		printf("Time set to %s", ctime(&resvalue));
	}
}

/*
 *	This function aids the sort in the main routine.
 *	It compares two unsigned longs and returns accordingly.
 */

#ifndef	pdp11
tcomp(first, second)
unsigned long *first, *second;
{
	if (*first < *second) {
		return(-1);
	} else if (*first > *second) {
		return(1);
	} else {
		return(0);
	}
}
#else	pdp11
tcomp(first, second)
long *first, *second;
{
	if (*first < 0 && *second >= 0) {
		return(1);
	} else if (*first >= 0 && *second < 0) {
		return(-1);
	} else if (*first < *second) {
		return(-1);
	} else if (*first > *second) {
		return(1);
	} else {
		return(0);
	}
}
#endif	pdp11