Ultrix-3.1/src/etc/rdate.c
/**********************************************************************
* 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