xref: /original-bsd/bin/date/date.c (revision 8df64c17)
1ad4dcd8fSsam #ifndef lint
2*8df64c17Sgusella static char sccsid[] = "@(#)date.c	4.7 (Berkeley) 06/17/85";
3*8df64c17Sgusella #endif not lint
4ad4dcd8fSsam 
563fd2155Sbill /*
6a3ca036fSleres  * Date - print and set date
7*8df64c17Sgusella  * Modified by Riccardo Gusella to work with timed
863fd2155Sbill  */
9a3ca036fSleres 
10*8df64c17Sgusella #include <sys/types.h>
11a3ca036fSleres #include <stdio.h>
1229f671e3Swnj #include <sys/time.h>
13*8df64c17Sgusella #include <sys/socket.h>
14*8df64c17Sgusella #include <netinet/in.h>
15*8df64c17Sgusella #include <netdb.h>
16*8df64c17Sgusella #define TSPTYPES
17*8df64c17Sgusella #include <protocols/timed.h>
18*8df64c17Sgusella #include <sys/file.h>
19*8df64c17Sgusella #include <errno.h>
20*8df64c17Sgusella #include <syslog.h>
2163fd2155Sbill #include <utmp.h>
22*8df64c17Sgusella 
23a3ca036fSleres #define WTMP "/usr/adm/wtmp"
24ad4dcd8fSsam 
25*8df64c17Sgusella struct	timeval tv, now;
26ad4dcd8fSsam struct	timezone tz;
2763fd2155Sbill char	*ap, *ep, *sp;
2863fd2155Sbill int	uflag;
2963fd2155Sbill 
3063fd2155Sbill char	*timezone();
3163fd2155Sbill static	int	dmsize[12] =
32ad4dcd8fSsam     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
33a3ca036fSleres static char *usage = "usage: date [-u] [yymmddhhmm[.ss]]\n";
3463fd2155Sbill 
353ebd153dSsam struct utmp wtmp[2] = {
363ebd153dSsam 	{ "|", "", "", 0 },
373ebd153dSsam 	{ "{", "", "", 0 }
383ebd153dSsam };
3963fd2155Sbill 
4063fd2155Sbill char	*ctime();
4163fd2155Sbill char	*asctime();
4263fd2155Sbill struct	tm *localtime();
4363fd2155Sbill struct	tm *gmtime();
4463fd2155Sbill 
45*8df64c17Sgusella char *strcpy();
46*8df64c17Sgusella char *username, *getlogin();
47*8df64c17Sgusella 
48*8df64c17Sgusella #define WAITACK		10	/* seconds */
49*8df64c17Sgusella #define WAITDATEACK	5	/* seconds */
50*8df64c17Sgusella 
51*8df64c17Sgusella int sock, length, port;
52*8df64c17Sgusella int ready, found;
53*8df64c17Sgusella char hostname[32];
54*8df64c17Sgusella struct timeval tout;
55*8df64c17Sgusella struct servent *srvp;
56*8df64c17Sgusella struct hostent *hp, *gethostbyname();
57*8df64c17Sgusella struct tsp msg;
58*8df64c17Sgusella struct sockaddr_in sin, dest, from;
59*8df64c17Sgusella 
6063fd2155Sbill main(argc, argv)
61ad4dcd8fSsam 	int argc;
6263fd2155Sbill 	char *argv[];
6363fd2155Sbill {
64*8df64c17Sgusella 	int wf;
65*8df64c17Sgusella 	int timed_ack;
6663fd2155Sbill 	register char *tzn;
67*8df64c17Sgusella 	int bytenetorder(), bytehostorder();
6863fd2155Sbill 
69*8df64c17Sgusella 	(void) gettimeofday(&tv, &tz);
70*8df64c17Sgusella 
71a3ca036fSleres 	if (argc > 1 && strcmp(argv[1], "-u") == 0) {
7263fd2155Sbill 		argc--;
7363fd2155Sbill 		argv++;
7463fd2155Sbill 		uflag++;
7563fd2155Sbill 	}
76*8df64c17Sgusella 	if (argc > 2) {
77*8df64c17Sgusella 		printf(usage);
78*8df64c17Sgusella 		exit(1);
79*8df64c17Sgusella 	}
80*8df64c17Sgusella 	if (argc == 1)
81*8df64c17Sgusella 		goto display;
82*8df64c17Sgusella 
83*8df64c17Sgusella 	if (getuid() != 0) {
84*8df64c17Sgusella 		printf("You are not superuser: date not set\n");
85*8df64c17Sgusella 		exit(1);
86*8df64c17Sgusella 	}
87*8df64c17Sgusella 	username = getlogin();
88*8df64c17Sgusella 	if (username == NULL) {
89*8df64c17Sgusella 		printf("Cannot record your name: date not set\n");
90*8df64c17Sgusella 		exit(1);
91*8df64c17Sgusella 	}
92*8df64c17Sgusella 	syslog(LOG_ERR, "date: set by %s", username);
93*8df64c17Sgusella 
9463fd2155Sbill 	ap = argv[1];
95c12caacaSralph 	wtmp[0].ut_time = tv.tv_sec;
9663fd2155Sbill 	if (gtime()) {
97a3ca036fSleres 		printf(usage);
9863fd2155Sbill 		exit(1);
9963fd2155Sbill 	}
10063fd2155Sbill 	/* convert to GMT assuming local time */
10163fd2155Sbill 	if (uflag == 0) {
102ad4dcd8fSsam 		tv.tv_sec += (long)tz.tz_minuteswest*60;
10363fd2155Sbill 		/* now fix up local daylight time */
104*8df64c17Sgusella 		if (localtime((long *)&tv.tv_sec)->tm_isdst)
105ad4dcd8fSsam 			tv.tv_sec -= 60*60;
10663fd2155Sbill 	}
107*8df64c17Sgusella 	(void) open("/etc/timed", O_WRONLY, 01700);
108*8df64c17Sgusella 	if (errno != ETXTBSY) {
109ad4dcd8fSsam 		if (settimeofday(&tv, (struct timezone *)0) < 0) {
110*8df64c17Sgusella 			perror("settimeofday");
111*8df64c17Sgusella 			exit(1);
112*8df64c17Sgusella 		}
113*8df64c17Sgusella 		if ((wf = open(WTMP, 1)) >= 0) {
114*8df64c17Sgusella 			(void) time((long *)&wtmp[1].ut_time);
115*8df64c17Sgusella 			(void) lseek(wf, (off_t)0L, 2);
116*8df64c17Sgusella 			(void) write(wf, (char *)wtmp, sizeof(wtmp));
117*8df64c17Sgusella 			(void) close(wf);
118*8df64c17Sgusella 		}
119*8df64c17Sgusella 		goto display;
120*8df64c17Sgusella 	}
121*8df64c17Sgusella 
122*8df64c17Sgusella /*
123*8df64c17Sgusella  * Here we set the date in the machines controlled by timedaemons
124*8df64c17Sgusella  * by communicating the new date to the local timedaemon.
125*8df64c17Sgusella  * If the timedaemon is in the master state, it performs the correction on
126*8df64c17Sgusella  * all slaves. If it is in the slave state, it notifies the master
127*8df64c17Sgusella  * that a correction is needed.
128*8df64c17Sgusella  */
129*8df64c17Sgusella 
130*8df64c17Sgusella 	srvp = getservbyname("timed", "udp");
131*8df64c17Sgusella 	if (srvp == 0) {
132*8df64c17Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
133*8df64c17Sgusella 		exit(1);
134*8df64c17Sgusella 	}
135*8df64c17Sgusella 	dest.sin_port = srvp->s_port;
136*8df64c17Sgusella 	dest.sin_family = AF_INET;
137*8df64c17Sgusella 	sock = socket(AF_INET, SOCK_DGRAM, 0);
138*8df64c17Sgusella 	if (sock < 0) {
139*8df64c17Sgusella 		perror("opening socket");
140*8df64c17Sgusella 		exit(1);
141*8df64c17Sgusella 	}
142*8df64c17Sgusella 
143*8df64c17Sgusella 	sin.sin_family = AF_INET;
144*8df64c17Sgusella 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
145*8df64c17Sgusella 		sin.sin_port = htons((u_short)port);
146*8df64c17Sgusella 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
147*8df64c17Sgusella 			break;
148*8df64c17Sgusella 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
149*8df64c17Sgusella 			perror("bind");
150*8df64c17Sgusella 			(void) close(sock);
151*8df64c17Sgusella 			exit(1);
15263fd2155Sbill 		}
15363fd2155Sbill 	}
154*8df64c17Sgusella 	if (port == IPPORT_RESERVED / 2) {
155*8df64c17Sgusella 		fprintf(stderr, "socket: All ports in use\n");
156*8df64c17Sgusella 		(void) close(sock);
157*8df64c17Sgusella 		exit(1);
158*8df64c17Sgusella 	}
159*8df64c17Sgusella 
160*8df64c17Sgusella 	(void) gethostname(hostname,sizeof(hostname));
161*8df64c17Sgusella 	hp = gethostbyname(hostname);
162*8df64c17Sgusella 	if (hp == NULL) {
163*8df64c17Sgusella 		perror("gethostbyname");
164*8df64c17Sgusella 		exit(1);
165*8df64c17Sgusella 	}
166*8df64c17Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
167*8df64c17Sgusella 
168*8df64c17Sgusella 	msg.tsp_type = TSP_DATE;
169*8df64c17Sgusella 	(void) strcpy(msg.tsp_name, hostname);
170*8df64c17Sgusella 	(void) gettimeofday(&now, (struct timezone *)0);
171*8df64c17Sgusella 	timevalsub(&tv, &now);
172*8df64c17Sgusella 	msg.tsp_time = tv;
173*8df64c17Sgusella 	bytenetorder(&msg);
174*8df64c17Sgusella 	length = sizeof(struct sockaddr_in);
175*8df64c17Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
176*8df64c17Sgusella 						&dest, length) < 0) {
177*8df64c17Sgusella 		perror("sendto");
178*8df64c17Sgusella 		exit(1);
179*8df64c17Sgusella 	}
180*8df64c17Sgusella 
181*8df64c17Sgusella 	timed_ack = -1;
182*8df64c17Sgusella 	tout.tv_sec = WAITACK;
183*8df64c17Sgusella 	tout.tv_usec = 0;
184*8df64c17Sgusella loop:
185*8df64c17Sgusella 	ready = 1<<sock;
186*8df64c17Sgusella 	found = select(20, &ready, (int *)0, (int *)0, &tout);
187*8df64c17Sgusella 	if (found) {
188*8df64c17Sgusella 		length = sizeof(struct sockaddr_in);
189*8df64c17Sgusella 		if (recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
190*8df64c17Sgusella 							&from, &length) < 0) {
191*8df64c17Sgusella 			perror("recvfrom");
192*8df64c17Sgusella 			exit(1);
193*8df64c17Sgusella 		}
194*8df64c17Sgusella 		bytehostorder(&msg);
195*8df64c17Sgusella 
196*8df64c17Sgusella 		switch (msg.tsp_type) {
197*8df64c17Sgusella 
198*8df64c17Sgusella 		case TSP_ACK:
199*8df64c17Sgusella 			timed_ack = TSP_ACK;
200*8df64c17Sgusella 			tout.tv_sec = WAITDATEACK;
201*8df64c17Sgusella 			tout.tv_usec = 0;
202*8df64c17Sgusella 			goto loop;
203*8df64c17Sgusella 			break;
204*8df64c17Sgusella 		case TSP_DATEACK:
205*8df64c17Sgusella 			goto display;
206*8df64c17Sgusella 			break;
207*8df64c17Sgusella 		default:
208*8df64c17Sgusella 			printf("Wrong ack received: %s\n",
209*8df64c17Sgusella 						tsptype[msg.tsp_type]);
210*8df64c17Sgusella 			timed_ack = -1;
211*8df64c17Sgusella 			break;
212*8df64c17Sgusella 		}
213*8df64c17Sgusella 	}
214*8df64c17Sgusella 
215*8df64c17Sgusella 	if (timed_ack == TSP_ACK) {
216*8df64c17Sgusella 		printf("Network date being set\n");
217*8df64c17Sgusella 		exit(0);
218*8df64c17Sgusella 	} else {
219*8df64c17Sgusella 		printf("Communication problems\n");
220*8df64c17Sgusella 		exit(1);
221*8df64c17Sgusella 	}
222*8df64c17Sgusella 
223*8df64c17Sgusella display:
224*8df64c17Sgusella 	(void) gettimeofday(&tv, (struct timezone *)0);
22563fd2155Sbill 	if (uflag) {
226*8df64c17Sgusella 		ap = asctime(gmtime((long *)&tv.tv_sec));
22763fd2155Sbill 		tzn = "GMT";
22863fd2155Sbill 	} else {
22963fd2155Sbill 		struct tm *tp;
230*8df64c17Sgusella 		tp = localtime((long *)&tv.tv_sec);
23163fd2155Sbill 		ap = asctime(tp);
232ad4dcd8fSsam 		tzn = timezone(tz.tz_minuteswest, tp->tm_isdst);
23363fd2155Sbill 	}
23463fd2155Sbill 	printf("%.20s", ap);
23563fd2155Sbill 	if (tzn)
23663fd2155Sbill 		printf("%s", tzn);
23763fd2155Sbill 	printf("%s", ap+19);
23863fd2155Sbill }
23963fd2155Sbill 
24063fd2155Sbill gtime()
24163fd2155Sbill {
24263fd2155Sbill 	register int i, year, month;
24363fd2155Sbill 	int day, hour, mins, secs;
24463fd2155Sbill 	struct tm *L;
24563fd2155Sbill 	char x;
24663fd2155Sbill 
24763fd2155Sbill 	ep = ap;
24863fd2155Sbill 	while(*ep) ep++;
24963fd2155Sbill 	sp = ap;
25063fd2155Sbill 	while(sp < ep) {
25163fd2155Sbill 		x = *sp;
25263fd2155Sbill 		*sp++ = *--ep;
25363fd2155Sbill 		*ep = x;
25463fd2155Sbill 	}
25563fd2155Sbill 	sp = ap;
256*8df64c17Sgusella 	(void) gettimeofday(&tv, (struct timezone *)0);
257*8df64c17Sgusella 	L = localtime((long *)&tv.tv_sec);
25863fd2155Sbill 	secs = gp(-1);
25963fd2155Sbill 	if (*sp != '.') {
26063fd2155Sbill 		mins = secs;
26163fd2155Sbill 		secs = 0;
262a3ca036fSleres 	} else {
263a3ca036fSleres 		sp++;
26463fd2155Sbill 		mins = gp(-1);
26563fd2155Sbill 	}
26663fd2155Sbill 	hour = gp(-1);
26763fd2155Sbill 	day = gp(L->tm_mday);
26863fd2155Sbill 	month = gp(L->tm_mon+1);
26963fd2155Sbill 	year = gp(L->tm_year);
27063fd2155Sbill 	if (*sp)
27163fd2155Sbill 		return (1);
27263fd2155Sbill 	if (month < 1 || month > 12 ||
27363fd2155Sbill 	    day < 1 || day > 31 ||
27463fd2155Sbill 	    mins < 0 || mins > 59 ||
27563fd2155Sbill 	    secs < 0 || secs > 59)
27663fd2155Sbill 		return (1);
27763fd2155Sbill 	if (hour == 24) {
278a3ca036fSleres 		hour = 0;
279a3ca036fSleres 		day++;
28063fd2155Sbill 	}
28163fd2155Sbill 	if (hour < 0 || hour > 23)
28263fd2155Sbill 		return (1);
283ad4dcd8fSsam 	tv.tv_sec = 0;
28463fd2155Sbill 	year += 1900;
28563fd2155Sbill 	for (i = 1970; i < year; i++)
286ad4dcd8fSsam 		tv.tv_sec += dysize(i);
28763fd2155Sbill 	/* Leap year */
28863fd2155Sbill 	if (dysize(year) == 366 && month >= 3)
289ad4dcd8fSsam 		tv.tv_sec++;
29063fd2155Sbill 	while (--month)
291ad4dcd8fSsam 		tv.tv_sec += dmsize[month-1];
292ad4dcd8fSsam 	tv.tv_sec += day-1;
293ad4dcd8fSsam 	tv.tv_sec = 24*tv.tv_sec + hour;
294ad4dcd8fSsam 	tv.tv_sec = 60*tv.tv_sec + mins;
295ad4dcd8fSsam 	tv.tv_sec = 60*tv.tv_sec + secs;
29663fd2155Sbill 	return (0);
29763fd2155Sbill }
29863fd2155Sbill 
29963fd2155Sbill gp(dfault)
30063fd2155Sbill {
30163fd2155Sbill 	register int c, d;
30263fd2155Sbill 
30363fd2155Sbill 	if (*sp == 0)
30463fd2155Sbill 		return (dfault);
30563fd2155Sbill 	c = (*sp++) - '0';
30663fd2155Sbill 	d = (*sp ? (*sp++) - '0' : 0);
30763fd2155Sbill 	if (c < 0 || c > 9 || d < 0 || d > 9)
30863fd2155Sbill 		return (-1);
30963fd2155Sbill 	return (c+10*d);
31063fd2155Sbill }
311*8df64c17Sgusella 
312*8df64c17Sgusella timevalsub(t1, t2)
313*8df64c17Sgusella struct timeval *t1, *t2;
314*8df64c17Sgusella {
315*8df64c17Sgusella 	t1->tv_sec -= t2->tv_sec;
316*8df64c17Sgusella 	t1->tv_usec -= t2->tv_usec;
317*8df64c17Sgusella 	if (t1->tv_usec < 0) {
318*8df64c17Sgusella 		t1->tv_sec--;
319*8df64c17Sgusella 		t1->tv_usec += 1000000;
320*8df64c17Sgusella 	}
321*8df64c17Sgusella 	if (t1->tv_usec >= 1000000) {
322*8df64c17Sgusella 		t1->tv_sec++;
323*8df64c17Sgusella 		t1->tv_usec -= 1000000;
324*8df64c17Sgusella 	}
325*8df64c17Sgusella }
326*8df64c17Sgusella 
327*8df64c17Sgusella bytenetorder(ptr)
328*8df64c17Sgusella struct tsp *ptr;
329*8df64c17Sgusella {
330*8df64c17Sgusella 	ptr->tsp_seq = htons((u_short)ptr->tsp_seq);
331*8df64c17Sgusella 	ptr->tsp_time.tv_sec = htonl((u_long)ptr->tsp_time.tv_sec);
332*8df64c17Sgusella 	ptr->tsp_time.tv_usec = htonl((u_long)ptr->tsp_time.tv_usec);
333*8df64c17Sgusella }
334*8df64c17Sgusella 
335*8df64c17Sgusella bytehostorder(ptr)
336*8df64c17Sgusella struct tsp *ptr;
337*8df64c17Sgusella {
338*8df64c17Sgusella 	ptr->tsp_seq = ntohs((u_short)ptr->tsp_seq);
339*8df64c17Sgusella 	ptr->tsp_time.tv_sec = ntohl((u_long)ptr->tsp_time.tv_sec);
340*8df64c17Sgusella 	ptr->tsp_time.tv_usec = ntohl((u_long)ptr->tsp_time.tv_usec);
341*8df64c17Sgusella }
342