new copyright notice
[unix-history] / usr / src / bin / date / date.c
CommitLineData
c9f81cd5 1/*
a9ff74ae
KB
2 * Copyright (c) 1985, 1987, 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
27c71911 5 * %sccs.include.redist.c%
c9f81cd5
KM
6 */
7
8#ifndef lint
9char copyright[] =
a9ff74ae 10"@(#) Copyright (c) 1985, 1987, 1988 The Regents of the University of California.\n\
c9f81cd5 11 All rights reserved.\n";
a9ff74ae 12#endif /* not lint */
c9f81cd5 13
e1d473bc 14#ifndef lint
27c71911 15static char sccsid[] = "@(#)date.c 4.27 (Berkeley) %G%";
a9ff74ae 16#endif /* not lint */
e1d473bc 17
0698cf89 18/*
5acde4b0 19 * Date - print and set date
0698cf89 20 */
5acde4b0 21
92463b23 22#include <sys/param.h>
72cf2549 23#include <sys/time.h>
08f42884
RG
24#include <sys/file.h>
25#include <errno.h>
26#include <syslog.h>
0698cf89 27#include <utmp.h>
a524e883
KB
28#include <tzfile.h>
29#include <stdio.h>
30#include <ctype.h>
6ebcb998 31#include <string.h>
08f42884 32
a524e883 33#define ATOI2(ar) (ar[0] - '0') * 10 + (ar[1] - '0'); ar += 2;
e1d473bc 34
a524e883
KB
35static struct timeval tv;
36static int retval;
0698cf89 37
a524e883
KB
38static int dmsize[] =
39 { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
0698cf89 40
a9ff74ae
KB
41main(argc, argv)
42 int argc;
43 char **argv;
0698cf89 44{
a9ff74ae
KB
45 extern int optind;
46 extern char *optarg;
47 struct timezone tz;
48 char *ap, *tzn;
49 int ch, uflag, nflag;
50 char *username, *getlogin();
51 time_t time();
08f42884 52
a524e883 53 nflag = uflag = 0;
b1290464 54 tz.tz_dsttime = tz.tz_minuteswest = 0;
a9ff74ae 55 while ((ch = getopt(argc, argv, "d:nut:")) != EOF)
a524e883 56 switch((char)ch) {
a9ff74ae 57 case 'd': /* daylight savings time */
a524e883 58 tz.tz_dsttime = atoi(optarg) ? 1 : 0;
f4cd17f6 59 break;
a9ff74ae 60 case 'n': /* don't set network */
a524e883 61 nflag = 1;
f4cd17f6 62 break;
a9ff74ae 63 case 'u': /* do it in GMT */
a524e883
KB
64 uflag = 1;
65 break;
a9ff74ae
KB
66 case 't': /* minutes west of GMT */
67 /* error check; we can't allow "PST" */
b1290464
KB
68 if (isdigit(*optarg)) {
69 tz.tz_minuteswest = atoi(optarg);
70 break;
71 }
72 /*FALLTHROUGH*/
a524e883 73 default:
b1290464 74 usage();
f4cd17f6
MK
75 exit(1);
76 }
a524e883
KB
77 argc -= optind;
78 argv += optind;
79
80 if (argc > 1) {
b1290464 81 usage();
a524e883 82 exit(1);
0698cf89 83 }
a524e883
KB
84
85 if ((tz.tz_minuteswest || tz.tz_dsttime) &&
a9ff74ae 86 settimeofday((struct timeval *)NULL, &tz)) {
4c49a121
KB
87 perror("date: settimeofday");
88 exit(1);
a524e883
KB
89 }
90
a9ff74ae 91 if (gettimeofday(&tv, &tz)) {
4c49a121 92 perror("date: gettimeofday");
08f42884
RG
93 exit(1);
94 }
a524e883
KB
95
96 if (!argc)
08f42884
RG
97 goto display;
98
a524e883 99 if (gtime(*argv)) {
b1290464 100 usage();
4c49a121 101 exit(1);
08f42884 102 }
a524e883
KB
103
104 if (!uflag) { /* convert to GMT assuming local time */
4c49a121 105 tv.tv_sec += (long)tz.tz_minuteswest * SECSPERMIN;
a524e883 106 /* now fix up local daylight time */
92463b23 107 if (localtime((time_t *)&tv.tv_sec)->tm_isdst)
4c49a121 108 tv.tv_sec -= SECSPERHOUR;
08f42884 109 }
a524e883 110 if (nflag || !netsettime(tv)) {
a9ff74ae
KB
111 logwtmp("|", "date", "");
112 if (settimeofday(&tv, (struct timezone *)NULL)) {
4c49a121
KB
113 perror("date: settimeofday");
114 exit(1);
92463b23 115 }
a9ff74ae 116 logwtmp("{", "date", "");
08f42884 117 }
a524e883
KB
118
119 username = getlogin();
120 if (!username || *username == '\0') /* single-user or no tty */
121 username = "root";
a9ff74ae 122 syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", username);
08f42884
RG
123
124display:
a9ff74ae 125 if (gettimeofday(&tv, (struct timezone *)NULL)) {
4c49a121 126 perror("date: gettimeofday");
a524e883
KB
127 exit(1);
128 }
e1d473bc 129 if (uflag) {
92463b23 130 ap = asctime(gmtime((time_t *)&tv.tv_sec));
0698cf89 131 tzn = "GMT";
a524e883
KB
132 }
133 else {
a9ff74ae 134 struct tm *tp;
a524e883 135
92463b23 136 tp = localtime((time_t *)&tv.tv_sec);
0698cf89 137 ap = asctime(tp);
a524e883 138 tzn = tp->tm_zone;
0698cf89 139 }
a9ff74ae 140 printf("%.20s%s%s", ap, tzn, ap + 19);
b2163cc6 141 exit(retval);
0698cf89
BJ
142}
143
a524e883
KB
144/*
145 * gtime --
146 * convert user's time into number of seconds
147 */
148static
149gtime(ap)
a9ff74ae 150 register char *ap;
0698cf89 151{
a9ff74ae
KB
152 register int year, month;
153 register char *C;
154 struct tm *L;
155 int day, hour, mins, secs;
a524e883 156
a9ff74ae 157 for (secs = 0, C = ap; *C; ++C) {
a524e883
KB
158 if (*C == '.') { /* seconds provided */
159 if (strlen(C) != 3)
160 return(1);
161 *C = NULL;
162 secs = (C[1] - '0') * 10 + (C[2] - '0');
163 break;
164 }
165 if (!isdigit(*C))
166 return(-1);
0698cf89 167 }
a524e883 168
92463b23 169 L = localtime((time_t *)&tv.tv_sec);
a524e883
KB
170 year = L->tm_year; /* defaults */
171 month = L->tm_mon + 1;
172 day = L->tm_mday;
173
174 switch ((int)(C - ap)) { /* length */
175 case 10: /* yymmddhhmm */
176 year = ATOI2(ap);
177 case 8: /* mmddhhmm */
178 month = ATOI2(ap);
179 case 6: /* ddhhmm */
180 day = ATOI2(ap);
181 case 4: /* hhmm */
182 hour = ATOI2(ap);
183 mins = ATOI2(ap);
184 break;
185 default:
186 return(1);
0698cf89 187 }
a524e883
KB
188
189 if (*ap || month < 1 || month > 12 || day < 1 || day > 31 ||
62a96c8b
KB
190 hour < 0 || hour > 23 || mins < 0 || mins > 59 ||
191 secs < 0 || secs > 59)
a524e883
KB
192 return(1);
193
e1d473bc 194 tv.tv_sec = 0;
a524e883
KB
195 year += TM_YEAR_BASE;
196 if (isleap(year) && month > 2)
197 ++tv.tv_sec;
198 for (--year;year >= EPOCH_YEAR;--year)
4c49a121 199 tv.tv_sec += isleap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
e1d473bc 200 while (--month)
a524e883
KB
201 tv.tv_sec += dmsize[month];
202 tv.tv_sec += day - 1;
4c49a121
KB
203 tv.tv_sec = HOURSPERDAY * tv.tv_sec + hour;
204 tv.tv_sec = MINSPERHOUR * tv.tv_sec + mins;
205 tv.tv_sec = SECSPERMIN * tv.tv_sec + secs;
a524e883 206 return(0);
0698cf89 207}
08f42884 208
f5ae02ee
MK
209#include <sys/socket.h>
210#include <netinet/in.h>
211#include <netdb.h>
212#define TSPTYPES
213#include <protocols/timed.h>
214
a9ff74ae
KB
215#define WAITACK 2 /* seconds */
216#define WAITDATEACK 5 /* seconds */
f5ae02ee
MK
217
218extern int errno;
219/*
220 * Set the date in the machines controlled by timedaemons
221 * by communicating the new date to the local timedaemon.
222 * If the timedaemon is in the master state, it performs the
223 * correction on all slaves. If it is in the slave state, it
224 * notifies the master that a correction is needed.
b2163cc6 225 * Returns 1 on success, 0 on failure.
f5ae02ee 226 */
a524e883
KB
227netsettime(ntv)
228 struct timeval ntv;
f5ae02ee
MK
229{
230 int s, length, port, timed_ack, found, err;
231 long waittime;
232 fd_set ready;
233 char hostname[MAXHOSTNAMELEN];
234 struct timeval tout;
235 struct servent *sp;
236 struct tsp msg;
237 struct sockaddr_in sin, dest, from;
238
239 sp = getservbyname("timed", "udp");
240 if (sp == 0) {
a9ff74ae 241 fputs("udp/timed: unknown service\n", stderr);
b2163cc6 242 retval = 2;
f5ae02ee 243 return (0);
a524e883 244 }
f5ae02ee
MK
245 dest.sin_port = sp->s_port;
246 dest.sin_family = AF_INET;
247 dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
248 s = socket(AF_INET, SOCK_DGRAM, 0);
249 if (s < 0) {
250 if (errno != EPROTONOSUPPORT)
251 perror("date: socket");
252 goto bad;
253 }
10629970 254 bzero((char *)&sin, sizeof (sin));
f5ae02ee
MK
255 sin.sin_family = AF_INET;
256 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
257 sin.sin_port = htons((u_short)port);
258 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
259 break;
260 if (errno != EADDRINUSE) {
261 if (errno != EADDRNOTAVAIL)
262 perror("date: bind");
263 goto bad;
264 }
265 }
266 if (port == IPPORT_RESERVED / 2) {
a9ff74ae 267 fputs("date: All ports in use\n", stderr);
f5ae02ee
MK
268 goto bad;
269 }
34a3a349 270 msg.tsp_type = TSP_SETDATE;
f5ae02ee 271 msg.tsp_vers = TSPVERSION;
a524e883 272 if (gethostname(hostname, sizeof (hostname))) {
4c49a121 273 perror("date: gethostname");
a524e883
KB
274 goto bad;
275 }
f5ae02ee 276 (void) strncpy(msg.tsp_name, hostname, sizeof (hostname));
f5ae02ee 277 msg.tsp_seq = htons((u_short)0);
a524e883
KB
278 msg.tsp_time.tv_sec = htonl((u_long)ntv.tv_sec);
279 msg.tsp_time.tv_usec = htonl((u_long)ntv.tv_usec);
f5ae02ee
MK
280 length = sizeof (struct sockaddr_in);
281 if (connect(s, &dest, length) < 0) {
282 perror("date: connect");
283 goto bad;
284 }
10629970 285 if (send(s, (char *)&msg, sizeof (struct tsp), 0) < 0) {
f5ae02ee
MK
286 if (errno != ECONNREFUSED)
287 perror("date: send");
288 goto bad;
289 }
290 timed_ack = -1;
291 waittime = WAITACK;
292loop:
293 tout.tv_sec = waittime;
294 tout.tv_usec = 0;
295 FD_ZERO(&ready);
296 FD_SET(s, &ready);
297 found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
298 length = sizeof(err);
10629970
JL
299 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &length) == 0
300 && err) {
f5ae02ee
MK
301 errno = err;
302 if (errno != ECONNREFUSED)
303 perror("date: send (delayed error)");
304 goto bad;
305 }
306 if (found > 0 && FD_ISSET(s, &ready)) {
307 length = sizeof (struct sockaddr_in);
10629970 308 if (recvfrom(s, (char *)&msg, sizeof (struct tsp), 0, &from,
f5ae02ee
MK
309 &length) < 0) {
310 if (errno != ECONNREFUSED)
311 perror("date: recvfrom");
312 goto bad;
313 }
314 msg.tsp_seq = ntohs(msg.tsp_seq);
315 msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
316 msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
317 switch (msg.tsp_type) {
318
319 case TSP_ACK:
320 timed_ack = TSP_ACK;
321 waittime = WAITDATEACK;
322 goto loop;
323
324 case TSP_DATEACK:
10629970 325 (void)close(s);
f5ae02ee
MK
326 return (1);
327
328 default:
329 fprintf(stderr,
330 "date: Wrong ack received from timed: %s\n",
331 tsptype[msg.tsp_type]);
332 timed_ack = -1;
333 break;
334 }
335 }
336 if (timed_ack == -1)
a524e883
KB
337 fputs("date: Can't reach time daemon, time set locally.\n",
338 stderr);
f5ae02ee 339bad:
10629970 340 (void)close(s);
b2163cc6 341 retval = 2;
f5ae02ee
MK
342 return (0);
343}
b1290464
KB
344
345usage()
346{
a9ff74ae 347 fputs("usage: date [-nu] [-d dst] [-t minutes_west] [yymmddhhmm[.ss]]\n", stderr);
b1290464 348}