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