Commit | Line | Data |
---|---|---|
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 | |
9 | char 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 | 15 | static 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 |
35 | static struct timeval tv; |
36 | static int retval; | |
0698cf89 | 37 | |
a524e883 KB |
38 | static int dmsize[] = |
39 | { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | |
0698cf89 | 40 | |
a9ff74ae KB |
41 | main(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 | |
124 | display: | |
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 | */ | |
148 | static | |
149 | gtime(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 | |
218 | extern 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 |
227 | netsettime(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; | |
292 | loop: | |
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 | 339 | bad: |
10629970 | 340 | (void)close(s); |
b2163cc6 | 341 | retval = 2; |
f5ae02ee MK |
342 | return (0); |
343 | } | |
b1290464 KB |
344 | |
345 | usage() | |
346 | { | |
a9ff74ae | 347 | fputs("usage: date [-nu] [-d dst] [-t minutes_west] [yymmddhhmm[.ss]]\n", stderr); |
b1290464 | 348 | } |