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