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