1e8f3668aSmckusick /* 2e8f3668aSmckusick * Copyright (c) 1985 Regents of the University of California. 3e8f3668aSmckusick * All rights reserved. The Berkeley software License Agreement 4e8f3668aSmckusick * specifies the terms and conditions for redistribution. 5e8f3668aSmckusick */ 6e8f3668aSmckusick 7ad4dcd8fSsam #ifndef lint 8e8f3668aSmckusick char copyright[] = 9e8f3668aSmckusick "@(#) Copyright (c) 1985 Regents of the University of California.\n\ 10e8f3668aSmckusick All rights reserved.\n"; 11e8f3668aSmckusick #endif not lint 12e8f3668aSmckusick 13e8f3668aSmckusick #ifndef lint 14*33de07beSbostic static char sccsid[] = "@(#)date.c 4.20 (Berkeley) 3/24/87"; 158df64c17Sgusella #endif not lint 16ad4dcd8fSsam 1763fd2155Sbill /* 18a3ca036fSleres * Date - print and set date 1963fd2155Sbill */ 20a3ca036fSleres 2136fa1a6bSkarels #include <sys/param.h> 2229f671e3Swnj #include <sys/time.h> 238df64c17Sgusella #include <sys/file.h> 248df64c17Sgusella #include <errno.h> 258df64c17Sgusella #include <syslog.h> 2663fd2155Sbill #include <utmp.h> 27fe3493caSbostic #include <tzfile.h> 28fe3493caSbostic #include <stdio.h> 29fe3493caSbostic #include <ctype.h> 30fe3493caSbostic #include <strings.h> 318df64c17Sgusella 32a3ca036fSleres #define WTMP "/usr/adm/wtmp" 33fe3493caSbostic #define ATOI2(ar) (ar[0] - '0') * 10 + (ar[1] - '0'); ar += 2; 34ad4dcd8fSsam 35fe3493caSbostic static struct timeval tv; 36fe3493caSbostic static int retval; 3763fd2155Sbill 38fe3493caSbostic static int dmsize[] = 39fe3493caSbostic { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 4063fd2155Sbill 41fe3493caSbostic static struct utmp wtmp[2] = { 423ebd153dSsam { "|", "", "", 0 }, 433ebd153dSsam { "{", "", "", 0 } 443ebd153dSsam }; 4563fd2155Sbill 4663fd2155Sbill main(argc,argv) 47ad4dcd8fSsam int argc; 48fe3493caSbostic char **argv; 4963fd2155Sbill { 50fe3493caSbostic extern int optind; 51fe3493caSbostic extern char *optarg; 52fe3493caSbostic struct timezone tz; 53fe3493caSbostic char *ap, /* time string */ 54fe3493caSbostic *tzn; /* time zone */ 55fe3493caSbostic int ch, /* getopts char */ 56fe3493caSbostic uflag, /* do it in GMT */ 57fe3493caSbostic nflag, /* only set time locally */ 58fe3493caSbostic wf; /* wtmp file descriptor */ 59fe3493caSbostic long time(); 60fe3493caSbostic uid_t getuid(); 61fe3493caSbostic char *username, *getlogin(); 6263fd2155Sbill 63fe3493caSbostic nflag = uflag = 0; 64*33de07beSbostic tz.tz_dsttime = tz.tz_minuteswest = 0; 65*33de07beSbostic while ((ch = getopt(argc,argv,"d:nut:")) != EOF) 66fe3493caSbostic switch((char)ch) { 67fe3493caSbostic case 'd': 68fe3493caSbostic tz.tz_dsttime = atoi(optarg) ? 1 : 0; 69fe3493caSbostic break; 701a1d0a1fSkarels case 'n': 71fe3493caSbostic nflag = 1; 721a1d0a1fSkarels break; 731a1d0a1fSkarels case 'u': 74fe3493caSbostic uflag = 1; 751a1d0a1fSkarels break; 76*33de07beSbostic case 't': /* error check; we can't allow "PST" */ 77*33de07beSbostic if (isdigit(*optarg)) { 78*33de07beSbostic tz.tz_minuteswest = atoi(optarg); 79*33de07beSbostic break; 80*33de07beSbostic } 81*33de07beSbostic /*FALLTHROUGH*/ 821a1d0a1fSkarels default: 83*33de07beSbostic usage(); 841a1d0a1fSkarels exit(1); 851a1d0a1fSkarels } 86fe3493caSbostic argc -= optind; 87fe3493caSbostic argv += optind; 88fe3493caSbostic 89fe3493caSbostic if (argc > 1) { 90*33de07beSbostic usage(); 918df64c17Sgusella exit(1); 928df64c17Sgusella } 938df64c17Sgusella 94fe3493caSbostic if ((tz.tz_minuteswest || tz.tz_dsttime) && 95fe3493caSbostic settimeofday((struct timeval *)NULL,&tz)) { 9636fa1a6bSkarels perror("settimeofday"); 97a645e934Slepreau retval = 1; 9836fa1a6bSkarels goto display; 9936fa1a6bSkarels } 100fe3493caSbostic 101fe3493caSbostic if (gettimeofday(&tv,&tz)) { 102fe3493caSbostic perror("gettimeofday"); 103fe3493caSbostic exit(1); 104fe3493caSbostic } 105fe3493caSbostic 106fe3493caSbostic if (!argc) 107fe3493caSbostic goto display; 108fe3493caSbostic 109fe3493caSbostic wtmp[0].ut_time = tv.tv_sec; 110fe3493caSbostic if (gtime(*argv)) { 111*33de07beSbostic usage(); 112fe3493caSbostic retval = 1; 113fe3493caSbostic goto display; 114fe3493caSbostic } 115fe3493caSbostic 116fe3493caSbostic if (!uflag) { /* convert to GMT assuming local time */ 117fe3493caSbostic tv.tv_sec += (long)tz.tz_minuteswest * SECS_PER_MIN; 118fe3493caSbostic /* now fix up local daylight time */ 119fe3493caSbostic if (localtime((time_t *)&tv.tv_sec)->tm_isdst) 120fe3493caSbostic tv.tv_sec -= SECS_PER_HOUR; 121fe3493caSbostic } 122fe3493caSbostic if (nflag || !netsettime(tv)) { 123fe3493caSbostic if (settimeofday(&tv,(struct timezone *)0)) { 124fe3493caSbostic perror("settimeofday"); 125fe3493caSbostic retval = 1; 126fe3493caSbostic goto display; 127fe3493caSbostic } 128fe3493caSbostic if ((wf = open(WTMP,O_WRONLY|O_APPEND)) < 0) 129fe3493caSbostic fputs("date: can't write wtmp file.\n",stderr); 130fe3493caSbostic else { 13136fa1a6bSkarels (void)time((time_t *)&wtmp[1].ut_time); 132fe3493caSbostic /*NOSTRICT*/ 13336fa1a6bSkarels (void)write(wf,(char *)wtmp,sizeof(wtmp)); 13436fa1a6bSkarels (void)close(wf); 13536fa1a6bSkarels } 1368df64c17Sgusella } 137fe3493caSbostic 138fe3493caSbostic username = getlogin(); 139fe3493caSbostic if (!username || *username == '\0') /* single-user or no tty */ 140fe3493caSbostic username = "root"; 141*33de07beSbostic syslog(LOG_AUTH | LOG_NOTICE,"date set by %s",username); 1428df64c17Sgusella 1438df64c17Sgusella display: 144fe3493caSbostic if (gettimeofday(&tv,(struct timezone *)0)) { 145fe3493caSbostic perror("gettimeofday"); 146fe3493caSbostic exit(1); 147fe3493caSbostic } 14863fd2155Sbill if (uflag) { 14936fa1a6bSkarels ap = asctime(gmtime((time_t *)&tv.tv_sec)); 15063fd2155Sbill tzn = "GMT"; 151fe3493caSbostic } 152fe3493caSbostic else { 15363fd2155Sbill struct tm *tp; 154fe3493caSbostic 15536fa1a6bSkarels tp = localtime((time_t *)&tv.tv_sec); 15663fd2155Sbill ap = asctime(tp); 157fe3493caSbostic tzn = tp->tm_zone; 15863fd2155Sbill } 159fe3493caSbostic printf("%.20s%s%s",ap,tzn,ap + 19); 160a645e934Slepreau exit(retval); 16163fd2155Sbill } 16263fd2155Sbill 163fe3493caSbostic /* 164fe3493caSbostic * gtime -- 165fe3493caSbostic * convert user's time into number of seconds 166fe3493caSbostic */ 167fe3493caSbostic static 168fe3493caSbostic gtime(ap) 169fe3493caSbostic register char *ap; /* user argument */ 17063fd2155Sbill { 171fe3493caSbostic register int year, month; 172fe3493caSbostic register char *C; /* pointer into time argument */ 17363fd2155Sbill struct tm *L; 174fe3493caSbostic int day, hour, mins, secs; 17563fd2155Sbill 176fe3493caSbostic for (secs = 0, C = ap;*C;++C) { 177fe3493caSbostic if (*C == '.') { /* seconds provided */ 178fe3493caSbostic if (strlen(C) != 3) 17963fd2155Sbill return(1); 180fe3493caSbostic *C = NULL; 181fe3493caSbostic secs = (C[1] - '0') * 10 + (C[2] - '0'); 182fe3493caSbostic break; 183fe3493caSbostic } 184fe3493caSbostic if (!isdigit(*C)) 185fe3493caSbostic return(-1); 186fe3493caSbostic } 187fe3493caSbostic 188fe3493caSbostic L = localtime((time_t *)&tv.tv_sec); 189fe3493caSbostic year = L->tm_year; /* defaults */ 190fe3493caSbostic month = L->tm_mon + 1; 191fe3493caSbostic day = L->tm_mday; 192fe3493caSbostic 193fe3493caSbostic switch ((int)(C - ap)) { /* length */ 194fe3493caSbostic case 10: /* yymmddhhmm */ 195fe3493caSbostic year = ATOI2(ap); 196fe3493caSbostic case 8: /* mmddhhmm */ 197fe3493caSbostic month = ATOI2(ap); 198fe3493caSbostic case 6: /* ddhhmm */ 199fe3493caSbostic day = ATOI2(ap); 200fe3493caSbostic case 4: /* hhmm */ 201fe3493caSbostic hour = ATOI2(ap); 202fe3493caSbostic mins = ATOI2(ap); 203fe3493caSbostic break; 204fe3493caSbostic default: 205fe3493caSbostic return(1); 206fe3493caSbostic } 207fe3493caSbostic 208fe3493caSbostic if (*ap || month < 1 || month > 12 || day < 1 || day > 31 || 209fe3493caSbostic mins < 0 || mins > 59 || secs < 0 || secs > 59) 21063fd2155Sbill return(1); 21163fd2155Sbill if (hour == 24) { 212fe3493caSbostic ++day; 213a3ca036fSleres hour = 0; 21463fd2155Sbill } 215fe3493caSbostic else if (hour < 0 || hour > 23) 21663fd2155Sbill return(1); 217fe3493caSbostic 218ad4dcd8fSsam tv.tv_sec = 0; 219fe3493caSbostic year += TM_YEAR_BASE; 220fe3493caSbostic if (isleap(year) && month > 2) 221fe3493caSbostic ++tv.tv_sec; 222fe3493caSbostic for (--year;year >= EPOCH_YEAR;--year) 223fe3493caSbostic tv.tv_sec += isleap(year) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR; 22463fd2155Sbill while (--month) 225fe3493caSbostic tv.tv_sec += dmsize[month]; 226ad4dcd8fSsam tv.tv_sec += day - 1; 227fe3493caSbostic tv.tv_sec = HOURS_PER_DAY * tv.tv_sec + hour; 228fe3493caSbostic tv.tv_sec = MINS_PER_HOUR * tv.tv_sec + mins; 229fe3493caSbostic tv.tv_sec = SECS_PER_MIN * tv.tv_sec + secs; 23063fd2155Sbill return(0); 23163fd2155Sbill } 23263fd2155Sbill 2331d873399Skarels #include <sys/socket.h> 2341d873399Skarels #include <netinet/in.h> 2351d873399Skarels #include <netdb.h> 2361d873399Skarels #define TSPTYPES 2371d873399Skarels #include <protocols/timed.h> 2381d873399Skarels 2391d873399Skarels #define WAITACK 2 /* seconds */ 2401d873399Skarels #define WAITDATEACK 5 /* seconds */ 2411d873399Skarels 2421d873399Skarels extern int errno; 2431d873399Skarels /* 2441d873399Skarels * Set the date in the machines controlled by timedaemons 2451d873399Skarels * by communicating the new date to the local timedaemon. 2461d873399Skarels * If the timedaemon is in the master state, it performs the 2471d873399Skarels * correction on all slaves. If it is in the slave state, it 2481d873399Skarels * notifies the master that a correction is needed. 249a645e934Slepreau * Returns 1 on success, 0 on failure. 2501d873399Skarels */ 251fe3493caSbostic static 252fe3493caSbostic netsettime(ntv) 253fe3493caSbostic struct timeval ntv; 2541d873399Skarels { 2551d873399Skarels int s, length, port, timed_ack, found, err; 2561d873399Skarels long waittime; 2571d873399Skarels fd_set ready; 2581d873399Skarels char hostname[MAXHOSTNAMELEN]; 2591d873399Skarels struct timeval tout; 2601d873399Skarels struct servent *sp; 2611d873399Skarels struct tsp msg; 2621d873399Skarels struct sockaddr_in sin, dest, from; 2631d873399Skarels 2641d873399Skarels sp = getservbyname("timed", "udp"); 2651d873399Skarels if (sp == 0) { 266fe3493caSbostic fputs("udp/timed: unknown service\n",stderr); 267a645e934Slepreau retval = 2; 2681d873399Skarels return (0); 2691d873399Skarels } 2701d873399Skarels dest.sin_port = sp->s_port; 2711d873399Skarels dest.sin_family = AF_INET; 2721d873399Skarels dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 2731d873399Skarels s = socket(AF_INET, SOCK_DGRAM, 0); 2741d873399Skarels if (s < 0) { 2751d873399Skarels if (errno != EPROTONOSUPPORT) 2761d873399Skarels perror("date: socket"); 2771d873399Skarels goto bad; 2781d873399Skarels } 2793416d647Slepreau bzero((char *)&sin, sizeof (sin)); 2801d873399Skarels sin.sin_family = AF_INET; 2811d873399Skarels for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 2821d873399Skarels sin.sin_port = htons((u_short)port); 2831d873399Skarels if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 2841d873399Skarels break; 2851d873399Skarels if (errno != EADDRINUSE) { 2861d873399Skarels if (errno != EADDRNOTAVAIL) 2871d873399Skarels perror("date: bind"); 2881d873399Skarels goto bad; 2891d873399Skarels } 2901d873399Skarels } 2911d873399Skarels if (port == IPPORT_RESERVED / 2) { 292fe3493caSbostic fputs("date: All ports in use\n",stderr); 2931d873399Skarels goto bad; 2941d873399Skarels } 295c37c46dcSbloom msg.tsp_type = TSP_SETDATE; 2961d873399Skarels msg.tsp_vers = TSPVERSION; 297fe3493caSbostic if (gethostname(hostname, sizeof (hostname))) { 298fe3493caSbostic perror("gethostname"); 299fe3493caSbostic goto bad; 300fe3493caSbostic } 3011d873399Skarels (void) strncpy(msg.tsp_name, hostname, sizeof (hostname)); 3021d873399Skarels msg.tsp_seq = htons((u_short)0); 303fe3493caSbostic msg.tsp_time.tv_sec = htonl((u_long)ntv.tv_sec); 304fe3493caSbostic msg.tsp_time.tv_usec = htonl((u_long)ntv.tv_usec); 3051d873399Skarels length = sizeof (struct sockaddr_in); 3061d873399Skarels if (connect(s, &dest, length) < 0) { 3071d873399Skarels perror("date: connect"); 3081d873399Skarels goto bad; 3091d873399Skarels } 3103416d647Slepreau if (send(s, (char *)&msg, sizeof (struct tsp), 0) < 0) { 3111d873399Skarels if (errno != ECONNREFUSED) 3121d873399Skarels perror("date: send"); 3131d873399Skarels goto bad; 3141d873399Skarels } 3151d873399Skarels timed_ack = -1; 3161d873399Skarels waittime = WAITACK; 3171d873399Skarels loop: 3181d873399Skarels tout.tv_sec = waittime; 3191d873399Skarels tout.tv_usec = 0; 3201d873399Skarels FD_ZERO(&ready); 3211d873399Skarels FD_SET(s, &ready); 3221d873399Skarels found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); 3231d873399Skarels length = sizeof(err); 3243416d647Slepreau if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &length) == 0 3253416d647Slepreau && err) { 3261d873399Skarels errno = err; 3271d873399Skarels if (errno != ECONNREFUSED) 3281d873399Skarels perror("date: send (delayed error)"); 3291d873399Skarels goto bad; 3301d873399Skarels } 3311d873399Skarels if (found > 0 && FD_ISSET(s, &ready)) { 3321d873399Skarels length = sizeof (struct sockaddr_in); 3333416d647Slepreau if (recvfrom(s, (char *)&msg, sizeof (struct tsp), 0, &from, 3341d873399Skarels &length) < 0) { 3351d873399Skarels if (errno != ECONNREFUSED) 3361d873399Skarels perror("date: recvfrom"); 3371d873399Skarels goto bad; 3381d873399Skarels } 3391d873399Skarels msg.tsp_seq = ntohs(msg.tsp_seq); 3401d873399Skarels msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 3411d873399Skarels msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 3421d873399Skarels switch (msg.tsp_type) { 3431d873399Skarels 3441d873399Skarels case TSP_ACK: 3451d873399Skarels timed_ack = TSP_ACK; 3461d873399Skarels waittime = WAITDATEACK; 3471d873399Skarels goto loop; 3481d873399Skarels 3491d873399Skarels case TSP_DATEACK: 3503416d647Slepreau (void)close(s); 3511d873399Skarels return (1); 3521d873399Skarels 3531d873399Skarels default: 3541d873399Skarels fprintf(stderr, 3551d873399Skarels "date: Wrong ack received from timed: %s\n", 3561d873399Skarels tsptype[msg.tsp_type]); 3571d873399Skarels timed_ack = -1; 3581d873399Skarels break; 3591d873399Skarels } 3601d873399Skarels } 3611d873399Skarels if (timed_ack == -1) 362fe3493caSbostic fputs("date: Can't reach time daemon, time set locally.\n", 363fe3493caSbostic stderr); 3641d873399Skarels bad: 3653416d647Slepreau (void)close(s); 366a645e934Slepreau retval = 2; 3671d873399Skarels return (0); 3681d873399Skarels } 369*33de07beSbostic 370*33de07beSbostic usage() 371*33de07beSbostic { 372*33de07beSbostic fputs("usage: date [-nu] [-d dst] [-t minutes_west] [yymmddhhmm[.ss]]\n",stderr); 373*33de07beSbostic } 374