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