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.17 (Berkeley) 04/29/86"; 15 #endif not lint 16 17 /* 18 * Date - print and set date 19 */ 20 21 #include <sys/param.h> 22 #include <stdio.h> 23 #include <sys/time.h> 24 #include <sys/file.h> 25 #include <errno.h> 26 #include <syslog.h> 27 #include <utmp.h> 28 29 #define WTMP "/usr/adm/wtmp" 30 31 struct timeval tv, now; 32 struct timezone tz; 33 char *ap, *ep, *sp; 34 int uflag, nflag; 35 36 char *timezone(); 37 static int dmsize[12] = 38 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 39 static char *usage = "usage: date [-n] [-u] [yymmddhhmm[.ss]]\n"; 40 41 struct utmp wtmp[2] = { 42 { "|", "", "", 0 }, 43 { "{", "", "", 0 } 44 }; 45 46 char *ctime(); 47 char *asctime(); 48 struct tm *localtime(); 49 struct tm *gmtime(); 50 char *strcpy(); 51 char *username, *getlogin(); 52 53 main(argc, argv) 54 int argc; 55 char *argv[]; 56 { 57 register char *tzn; 58 59 openlog("date", LOG_ODELAY, LOG_AUTH); 60 (void) gettimeofday(&tv, &tz); 61 now = tv; 62 63 while (argc > 1 && argv[1][0] == '-') { 64 while (*++argv[1]) 65 switch ((int)argv[1][0]) { 66 67 case 'n': 68 nflag++; 69 break; 70 71 case 'u': 72 uflag++; 73 break; 74 75 default: 76 printf(usage); 77 exit(1); 78 } 79 argc--; 80 argv++; 81 } 82 if (argc > 2) { 83 printf(usage); 84 exit(1); 85 } 86 if (argc == 1) 87 goto display; 88 89 if (getuid() != 0) { 90 printf("You are not superuser: date not set\n"); 91 goto display; 92 } 93 username = getlogin(); 94 if (username == NULL) /* single-user or no tty */ 95 username = "root"; 96 97 ap = argv[1]; 98 wtmp[0].ut_time = tv.tv_sec; 99 if (gtime()) { 100 printf(usage); 101 goto display; 102 } 103 /* convert to GMT assuming local time */ 104 if (uflag == 0) { 105 tv.tv_sec += (long)tz.tz_minuteswest*60; 106 /* now fix up local daylight time */ 107 if (localtime((time_t *)&tv.tv_sec)->tm_isdst) 108 tv.tv_sec -= 60*60; 109 } 110 if (nflag || !settime(tv)) { 111 int wf; 112 113 if (settimeofday(&tv, (struct timezone *)0) < 0) { 114 perror("settimeofday"); 115 goto display; 116 } 117 if ((wf = open(WTMP, O_WRONLY|O_APPEND)) >= 0) { 118 (void) time((time_t *)&wtmp[1].ut_time); 119 (void) write(wf, (char *)wtmp, sizeof(wtmp)); 120 (void) close(wf); 121 } 122 } 123 syslog(LOG_NOTICE, "set by %s", username); 124 125 display: 126 (void) gettimeofday(&tv, (struct timezone *)0); 127 if (uflag) { 128 ap = asctime(gmtime((time_t *)&tv.tv_sec)); 129 tzn = "GMT"; 130 } else { 131 struct tm *tp; 132 tp = localtime((time_t *)&tv.tv_sec); 133 ap = asctime(tp); 134 tzn = timezone(tz.tz_minuteswest, tp->tm_isdst); 135 } 136 printf("%.20s", ap); 137 if (tzn) 138 printf("%s", tzn); 139 printf("%s", ap+19); 140 } 141 142 gtime() 143 { 144 register int i, year, month; 145 int day, hour, mins, secs; 146 struct tm *L; 147 char x; 148 149 ep = ap; 150 while(*ep) ep++; 151 sp = ap; 152 while(sp < ep) { 153 x = *sp; 154 *sp++ = *--ep; 155 *ep = x; 156 } 157 sp = ap; 158 (void) gettimeofday(&tv, (struct timezone *)0); 159 L = localtime((time_t *)&tv.tv_sec); 160 secs = gp(-1); 161 if (*sp != '.') { 162 mins = secs; 163 secs = 0; 164 } else { 165 sp++; 166 mins = gp(-1); 167 } 168 hour = gp(-1); 169 day = gp(L->tm_mday); 170 month = gp(L->tm_mon+1); 171 year = gp(L->tm_year); 172 if (*sp) 173 return (1); 174 if (month < 1 || month > 12 || 175 day < 1 || day > 31 || 176 mins < 0 || mins > 59 || 177 secs < 0 || secs > 59) 178 return (1); 179 if (hour == 24) { 180 hour = 0; 181 day++; 182 } 183 if (hour < 0 || hour > 23) 184 return (1); 185 tv.tv_sec = 0; 186 year += 1900; 187 for (i = 1970; i < year; i++) 188 tv.tv_sec += dysize(i); 189 /* Leap year */ 190 if (dysize(year) == 366 && month >= 3) 191 tv.tv_sec++; 192 while (--month) 193 tv.tv_sec += dmsize[month-1]; 194 tv.tv_sec += day-1; 195 tv.tv_sec = 24*tv.tv_sec + hour; 196 tv.tv_sec = 60*tv.tv_sec + mins; 197 tv.tv_sec = 60*tv.tv_sec + secs; 198 return (0); 199 } 200 201 gp(dfault) 202 { 203 register int c, d; 204 205 if (*sp == 0) 206 return (dfault); 207 c = (*sp++) - '0'; 208 d = (*sp ? (*sp++) - '0' : 0); 209 if (c < 0 || c > 9 || d < 0 || d > 9) 210 return (-1); 211 return (c+10*d); 212 } 213 214 #include <sys/socket.h> 215 #include <netinet/in.h> 216 #include <netdb.h> 217 #define TSPTYPES 218 #include <protocols/timed.h> 219 220 #define WAITACK 2 /* seconds */ 221 #define WAITDATEACK 5 /* seconds */ 222 223 extern int errno; 224 /* 225 * Set the date in the machines controlled by timedaemons 226 * by communicating the new date to the local timedaemon. 227 * If the timedaemon is in the master state, it performs the 228 * correction on all slaves. If it is in the slave state, it 229 * notifies the master that a correction is needed. 230 */ 231 settime(tv) 232 struct timeval tv; 233 { 234 int s, length, port, timed_ack, found, err; 235 long waittime; 236 fd_set ready; 237 char hostname[MAXHOSTNAMELEN]; 238 struct timeval tout; 239 struct servent *sp; 240 struct tsp msg; 241 struct sockaddr_in sin, dest, from; 242 243 sp = getservbyname("timed", "udp"); 244 if (sp == 0) { 245 fprintf(stderr, "udp/timed: unknown service\n"); 246 return (0); 247 } 248 dest.sin_port = sp->s_port; 249 dest.sin_family = AF_INET; 250 dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 251 s = socket(AF_INET, SOCK_DGRAM, 0); 252 if (s < 0) { 253 if (errno != EPROTONOSUPPORT) 254 perror("date: socket"); 255 goto bad; 256 } 257 bzero(&sin, sizeof (sin)); 258 sin.sin_family = AF_INET; 259 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 260 sin.sin_port = htons((u_short)port); 261 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 262 break; 263 if (errno != EADDRINUSE) { 264 if (errno != EADDRNOTAVAIL) 265 perror("date: bind"); 266 goto bad; 267 } 268 } 269 if (port == IPPORT_RESERVED / 2) { 270 fprintf(stderr, "date: All ports in use\n"); 271 goto bad; 272 } 273 msg.tsp_type = TSP_SETDATE; 274 msg.tsp_vers = TSPVERSION; 275 (void) gethostname(hostname, sizeof (hostname)); 276 (void) strncpy(msg.tsp_name, hostname, sizeof (hostname)); 277 msg.tsp_seq = htons((u_short)0); 278 msg.tsp_time.tv_sec = htonl((u_long)tv.tv_sec); 279 msg.tsp_time.tv_usec = htonl((u_long)tv.tv_usec); 280 length = sizeof (struct sockaddr_in); 281 if (connect(s, &dest, length) < 0) { 282 perror("date: connect"); 283 goto bad; 284 } 285 if (send(s, &msg, sizeof (struct tsp), 0) < 0) { 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); 299 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &length) == 0 && err) { 300 errno = err; 301 if (errno != ECONNREFUSED) 302 perror("date: send (delayed error)"); 303 goto bad; 304 } 305 if (found > 0 && FD_ISSET(s, &ready)) { 306 length = sizeof (struct sockaddr_in); 307 if (recvfrom(s, &msg, sizeof (struct tsp), 0, &from, 308 &length) < 0) { 309 if (errno != ECONNREFUSED) 310 perror("date: recvfrom"); 311 goto bad; 312 } 313 msg.tsp_seq = ntohs(msg.tsp_seq); 314 msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 315 msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 316 switch (msg.tsp_type) { 317 318 case TSP_ACK: 319 timed_ack = TSP_ACK; 320 waittime = WAITDATEACK; 321 goto loop; 322 323 case TSP_DATEACK: 324 close(s); 325 return (1); 326 327 default: 328 fprintf(stderr, 329 "date: Wrong ack received from timed: %s\n", 330 tsptype[msg.tsp_type]); 331 timed_ack = -1; 332 break; 333 } 334 } 335 if (timed_ack == -1) 336 fprintf(stderr, 337 "date: Can't reach time daemon, time set locally.\n"); 338 bad: 339 close(s); 340 return (0); 341 } 342 343 timevalsub(t1, t2) 344 register struct timeval *t1, *t2; 345 { 346 t1->tv_sec -= t2->tv_sec; 347 t1->tv_usec -= t2->tv_usec; 348 if (t1->tv_usec < 0) { 349 t1->tv_sec--; 350 t1->tv_usec += 1000000; 351 } 352 if (t1->tv_usec >= 1000000) { 353 t1->tv_sec++; 354 t1->tv_usec -= 1000000; 355 } 356 } 357