rdate.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 287 行

C
287
字号
#ifndef lintstatic	char	*sccsid = "@(#)rdate.c	4.2	(ULTRIX)	9/7/90";#endif lint/************************************************************************ *									* *			Copyright (c) 1985,86 by			* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//*----------------------------------------------------------------------- *	Modification History * *      9/06/90 -- terry *              Modified code to use correct network address for  *              finding the time on a specific network. *              Also added exit(1) after "unknown network" message to *              exit gracefully. * *	4/15/85 -- jrs *		Use INADDR_BROADCAST as default when none specified *		to get around subnet addr problems. * *	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 broadcast addr to 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>#include <sys/time.h>#include <netinet/in.h>#define	WTMP	"/usr/adm/wtmp"#define	RESMAX	100struct	utmp wtmp[2] = { { "|", "", "", 0 }, { "{", "", "", 0 } };struct	servent *getservbyname();struct	netent *getnetbyname();struct	hostent *gethostbyname();struct	in_addr inet_makeaddr();int	tcomp();main(argc, argv)int	argc;char	**argv;{	int	set = 0;	int	verbose = 0;	int	on = 1;	char	*net = NULL;	struct	servent	*tserv;	struct	netent	*tnet;	struct	hostent	*thost;	struct	sockaddr_in netaddr;	struct	timeval baset, nowt, timeout;	struct	timezone basez, nowz;	char	hostnam[32], resbuf[16], *swtp;	int	argp, wtmpfd, tsock, readsel, writesel, selmax, selvalue;	int	rescount, median, addrsiz;	unsigned long reslist[RESMAX], resvalue;	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];		}	}	/* 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) {		netaddr.sin_addr.s_addr = INADDR_BROADCAST;	} else {		if ((tnet = getnetbyname(net)) == NULL) {			fprintf(stderr, "%s: Unknown network - %s\n",					argv[0], net);			exit(1);		}		netaddr.sin_addr = inet_makeaddr(tnet->n_net, INADDR_ANY);	}	/* 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);	}	(void) gettimeofday(&baset, &basez);	/* set up for select, then yell for someone to tell us the time */	timeout.tv_sec = 2;	timeout.tv_usec = 0;	readsel = 1 << tsock;	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 */	while ((selvalue = select(selmax, &readsel, &writesel, &writesel,				&timeout)) > 0) {		/* reset for next select */		timeout.tv_sec = 2;		timeout.tv_usec = 0;		readsel = 1 << tsock;		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 */		(void) gettimeofday(&nowt, &nowz);		resvalue = ntohl(*(unsigned long *)resbuf) - 2208988800l;		reslist[rescount++] = resvalue - (nowt.tv_sec - baset.tv_sec);		/* 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 */	(void) gettimeofday(&nowt, &nowz);	resvalue = reslist[median] + (nowt.tv_sec - baset.tv_sec);	/* if setting, do it, otherwise just print conclusions */	if (set == 0) {		fprintf(stderr, "Network time is %s", ctime(&resvalue));	} else {		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);		}		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. */tcomp(first, second)unsigned long *first, *second;{	if (*first < *second) {		return(-1);	} else if (*first > *second) {		return(1);	} else {		return(0);	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?