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*fe3493caSbostic static char sccsid[] = "@(#)date.c 4.20 (Berkeley) 03/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> 27*fe3493caSbostic #include <tzfile.h> 28*fe3493caSbostic #include <stdio.h> 29*fe3493caSbostic #include <ctype.h> 30*fe3493caSbostic #include <strings.h> 318df64c17Sgusella 32a3ca036fSleres #define WTMP "/usr/adm/wtmp" 33*fe3493caSbostic #define ATOI2(ar) (ar[0] - '0') * 10 + (ar[1] - '0'); ar += 2; 34ad4dcd8fSsam 35*fe3493caSbostic static struct timeval tv; 36*fe3493caSbostic static int retval; 3763fd2155Sbill 38*fe3493caSbostic static int dmsize[] = 39*fe3493caSbostic { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 4063fd2155Sbill 41*fe3493caSbostic static struct utmp wtmp[2] = { 423ebd153dSsam { "|", "", "", 0 }, 433ebd153dSsam { "{", "", "", 0 } 443ebd153dSsam }; 4563fd2155Sbill 4663fd2155Sbill main(argc,argv) 47ad4dcd8fSsam int argc; 48*fe3493caSbostic char **argv; 4963fd2155Sbill { 50*fe3493caSbostic extern int optind; 51*fe3493caSbostic extern char *optarg; 52*fe3493caSbostic static char usage[] = "usage: date [-n] [-u] [yymmddhhmm[.ss]]\n"; 53*fe3493caSbostic struct timezone tz; 54*fe3493caSbostic char *ap, /* time string */ 55*fe3493caSbostic *tzn; /* time zone */ 56*fe3493caSbostic int ch, /* getopts char */ 57*fe3493caSbostic uflag, /* do it in GMT */ 58*fe3493caSbostic nflag, /* only set time locally */ 59*fe3493caSbostic wf; /* wtmp file descriptor */ 60*fe3493caSbostic long time(); 61*fe3493caSbostic uid_t getuid(); 62*fe3493caSbostic char *username, *getlogin(); 6363fd2155Sbill 64b3f53864Seric openlog("date", LOG_ODELAY, LOG_AUTH); 658df64c17Sgusella 66*fe3493caSbostic nflag = uflag = 0; 67*fe3493caSbostic while ((ch = getopt(argc,argv,"nu")) != EOF) 68*fe3493caSbostic switch((char)ch) { 69*fe3493caSbostic case 'd': 70*fe3493caSbostic tz.tz_dsttime = atoi(optarg) ? 1 : 0; 71*fe3493caSbostic break; 721a1d0a1fSkarels case 'n': 73*fe3493caSbostic nflag = 1; 741a1d0a1fSkarels break; 75*fe3493caSbostic case 't': 76*fe3493caSbostic tz.tz_minuteswest = atoi(optarg); 77*fe3493caSbostic break; 781a1d0a1fSkarels case 'u': 79*fe3493caSbostic uflag = 1; 801a1d0a1fSkarels break; 811a1d0a1fSkarels default: 82*fe3493caSbostic fputs(usage,stderr); 831a1d0a1fSkarels exit(1); 841a1d0a1fSkarels } 85*fe3493caSbostic argc -= optind; 86*fe3493caSbostic argv += optind; 87*fe3493caSbostic 88*fe3493caSbostic if (argc > 1) { 89*fe3493caSbostic fputs(usage,stderr); 908df64c17Sgusella exit(1); 918df64c17Sgusella } 928df64c17Sgusella 93*fe3493caSbostic if ((tz.tz_minuteswest || tz.tz_dsttime) && 94*fe3493caSbostic settimeofday((struct timeval *)NULL,&tz)) { 9536fa1a6bSkarels perror("settimeofday"); 96a645e934Slepreau retval = 1; 9736fa1a6bSkarels goto display; 9836fa1a6bSkarels } 99*fe3493caSbostic 100*fe3493caSbostic if (gettimeofday(&tv,&tz)) { 101*fe3493caSbostic perror("gettimeofday"); 102*fe3493caSbostic exit(1); 103*fe3493caSbostic } 104*fe3493caSbostic 105*fe3493caSbostic if (!argc) 106*fe3493caSbostic goto display; 107*fe3493caSbostic 108*fe3493caSbostic if (getuid()) { 109*fe3493caSbostic fputs("You are not superuser: date not set.\n",stderr); 110*fe3493caSbostic retval = 1; 111*fe3493caSbostic goto display; 112*fe3493caSbostic } 113*fe3493caSbostic 114*fe3493caSbostic wtmp[0].ut_time = tv.tv_sec; 115*fe3493caSbostic if (gtime(*argv)) { 116*fe3493caSbostic fprintf(stderr,usage); 117*fe3493caSbostic retval = 1; 118*fe3493caSbostic goto display; 119*fe3493caSbostic } 120*fe3493caSbostic 121*fe3493caSbostic if (!uflag) { /* convert to GMT assuming local time */ 122*fe3493caSbostic tv.tv_sec += (long)tz.tz_minuteswest * SECS_PER_MIN; 123*fe3493caSbostic /* now fix up local daylight time */ 124*fe3493caSbostic if (localtime((time_t *)&tv.tv_sec)->tm_isdst) 125*fe3493caSbostic tv.tv_sec -= SECS_PER_HOUR; 126*fe3493caSbostic } 127*fe3493caSbostic if (nflag || !netsettime(tv)) { 128*fe3493caSbostic if (settimeofday(&tv,(struct timezone *)0)) { 129*fe3493caSbostic perror("settimeofday"); 130*fe3493caSbostic retval = 1; 131*fe3493caSbostic goto display; 132*fe3493caSbostic } 133*fe3493caSbostic if ((wf = open(WTMP,O_WRONLY|O_APPEND)) < 0) 134*fe3493caSbostic fputs("date: can't write wtmp file.\n",stderr); 135*fe3493caSbostic else { 13636fa1a6bSkarels (void)time((time_t *)&wtmp[1].ut_time); 137*fe3493caSbostic /*NOSTRICT*/ 13836fa1a6bSkarels (void)write(wf,(char *)wtmp,sizeof(wtmp)); 13936fa1a6bSkarels (void)close(wf); 14036fa1a6bSkarels } 1418df64c17Sgusella } 142*fe3493caSbostic 143*fe3493caSbostic username = getlogin(); 144*fe3493caSbostic if (!username || *username == '\0') /* single-user or no tty */ 145*fe3493caSbostic username = "root"; 1461d873399Skarels syslog(LOG_NOTICE,"set by %s",username); 1478df64c17Sgusella 1488df64c17Sgusella display: 149*fe3493caSbostic if (gettimeofday(&tv,(struct timezone *)0)) { 150*fe3493caSbostic perror("gettimeofday"); 151*fe3493caSbostic exit(1); 152*fe3493caSbostic } 15363fd2155Sbill if (uflag) { 15436fa1a6bSkarels ap = asctime(gmtime((time_t *)&tv.tv_sec)); 15563fd2155Sbill tzn = "GMT"; 156*fe3493caSbostic } 157*fe3493caSbostic else { 15863fd2155Sbill struct tm *tp; 159*fe3493caSbostic 16036fa1a6bSkarels tp = localtime((time_t *)&tv.tv_sec); 16163fd2155Sbill ap = asctime(tp); 162*fe3493caSbostic tzn = tp->tm_zone; 16363fd2155Sbill } 164*fe3493caSbostic printf("%.20s%s%s",ap,tzn,ap + 19); 165a645e934Slepreau exit(retval); 16663fd2155Sbill } 16763fd2155Sbill 168*fe3493caSbostic /* 169*fe3493caSbostic * gtime -- 170*fe3493caSbostic * convert user's time into number of seconds 171*fe3493caSbostic */ 172*fe3493caSbostic static 173*fe3493caSbostic gtime(ap) 174*fe3493caSbostic register char *ap; /* user argument */ 17563fd2155Sbill { 176*fe3493caSbostic register int year, month; 177*fe3493caSbostic register char *C; /* pointer into time argument */ 17863fd2155Sbill struct tm *L; 179*fe3493caSbostic int day, hour, mins, secs; 18063fd2155Sbill 181*fe3493caSbostic for (secs = 0, C = ap;*C;++C) { 182*fe3493caSbostic if (*C == '.') { /* seconds provided */ 183*fe3493caSbostic if (strlen(C) != 3) 18463fd2155Sbill return(1); 185*fe3493caSbostic *C = NULL; 186*fe3493caSbostic secs = (C[1] - '0') * 10 + (C[2] - '0'); 187*fe3493caSbostic break; 188*fe3493caSbostic } 189*fe3493caSbostic if (!isdigit(*C)) 190*fe3493caSbostic return(-1); 191*fe3493caSbostic } 192*fe3493caSbostic 193*fe3493caSbostic L = localtime((time_t *)&tv.tv_sec); 194*fe3493caSbostic year = L->tm_year; /* defaults */ 195*fe3493caSbostic month = L->tm_mon + 1; 196*fe3493caSbostic day = L->tm_mday; 197*fe3493caSbostic 198*fe3493caSbostic switch ((int)(C - ap)) { /* length */ 199*fe3493caSbostic case 10: /* yymmddhhmm */ 200*fe3493caSbostic year = ATOI2(ap); 201*fe3493caSbostic case 8: /* mmddhhmm */ 202*fe3493caSbostic month = ATOI2(ap); 203*fe3493caSbostic case 6: /* ddhhmm */ 204*fe3493caSbostic day = ATOI2(ap); 205*fe3493caSbostic case 4: /* hhmm */ 206*fe3493caSbostic hour = ATOI2(ap); 207*fe3493caSbostic mins = ATOI2(ap); 208*fe3493caSbostic break; 209*fe3493caSbostic default: 210*fe3493caSbostic return(1); 211*fe3493caSbostic } 212*fe3493caSbostic 213*fe3493caSbostic if (*ap || month < 1 || month > 12 || day < 1 || day > 31 || 214*fe3493caSbostic mins < 0 || mins > 59 || secs < 0 || secs > 59) 21563fd2155Sbill return(1); 21663fd2155Sbill if (hour == 24) { 217*fe3493caSbostic ++day; 218a3ca036fSleres hour = 0; 21963fd2155Sbill } 220*fe3493caSbostic else if (hour < 0 || hour > 23) 22163fd2155Sbill return(1); 222*fe3493caSbostic 223ad4dcd8fSsam tv.tv_sec = 0; 224*fe3493caSbostic year += TM_YEAR_BASE; 225*fe3493caSbostic if (isleap(year) && month > 2) 226*fe3493caSbostic ++tv.tv_sec; 227*fe3493caSbostic for (--year;year >= EPOCH_YEAR;--year) 228*fe3493caSbostic tv.tv_sec += isleap(year) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR; 22963fd2155Sbill while (--month) 230*fe3493caSbostic tv.tv_sec += dmsize[month]; 231ad4dcd8fSsam tv.tv_sec += day - 1; 232*fe3493caSbostic tv.tv_sec = HOURS_PER_DAY * tv.tv_sec + hour; 233*fe3493caSbostic tv.tv_sec = MINS_PER_HOUR * tv.tv_sec + mins; 234*fe3493caSbostic tv.tv_sec = SECS_PER_MIN * tv.tv_sec + secs; 23563fd2155Sbill return(0); 23663fd2155Sbill } 23763fd2155Sbill 2381d873399Skarels #include <sys/socket.h> 2391d873399Skarels #include <netinet/in.h> 2401d873399Skarels #include <netdb.h> 2411d873399Skarels #define TSPTYPES 2421d873399Skarels #include <protocols/timed.h> 2431d873399Skarels 2441d873399Skarels #define WAITACK 2 /* seconds */ 2451d873399Skarels #define WAITDATEACK 5 /* seconds */ 2461d873399Skarels 2471d873399Skarels extern int errno; 2481d873399Skarels /* 2491d873399Skarels * Set the date in the machines controlled by timedaemons 2501d873399Skarels * by communicating the new date to the local timedaemon. 2511d873399Skarels * If the timedaemon is in the master state, it performs the 2521d873399Skarels * correction on all slaves. If it is in the slave state, it 2531d873399Skarels * notifies the master that a correction is needed. 254a645e934Slepreau * Returns 1 on success, 0 on failure. 2551d873399Skarels */ 256*fe3493caSbostic static 257*fe3493caSbostic netsettime(ntv) 258*fe3493caSbostic struct timeval ntv; 2591d873399Skarels { 2601d873399Skarels int s, length, port, timed_ack, found, err; 2611d873399Skarels long waittime; 2621d873399Skarels fd_set ready; 2631d873399Skarels char hostname[MAXHOSTNAMELEN]; 2641d873399Skarels struct timeval tout; 2651d873399Skarels struct servent *sp; 2661d873399Skarels struct tsp msg; 2671d873399Skarels struct sockaddr_in sin, dest, from; 2681d873399Skarels 2691d873399Skarels sp = getservbyname("timed", "udp"); 2701d873399Skarels if (sp == 0) { 271*fe3493caSbostic fputs("udp/timed: unknown service\n",stderr); 272a645e934Slepreau retval = 2; 2731d873399Skarels return (0); 2741d873399Skarels } 2751d873399Skarels dest.sin_port = sp->s_port; 2761d873399Skarels dest.sin_family = AF_INET; 2771d873399Skarels dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 2781d873399Skarels s = socket(AF_INET, SOCK_DGRAM, 0); 2791d873399Skarels if (s < 0) { 2801d873399Skarels if (errno != EPROTONOSUPPORT) 2811d873399Skarels perror("date: socket"); 2821d873399Skarels goto bad; 2831d873399Skarels } 2843416d647Slepreau bzero((char *)&sin, sizeof (sin)); 2851d873399Skarels sin.sin_family = AF_INET; 2861d873399Skarels for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 2871d873399Skarels sin.sin_port = htons((u_short)port); 2881d873399Skarels if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 2891d873399Skarels break; 2901d873399Skarels if (errno != EADDRINUSE) { 2911d873399Skarels if (errno != EADDRNOTAVAIL) 2921d873399Skarels perror("date: bind"); 2931d873399Skarels goto bad; 2941d873399Skarels } 2951d873399Skarels } 2961d873399Skarels if (port == IPPORT_RESERVED / 2) { 297*fe3493caSbostic fputs("date: All ports in use\n",stderr); 2981d873399Skarels goto bad; 2991d873399Skarels } 300c37c46dcSbloom msg.tsp_type = TSP_SETDATE; 3011d873399Skarels msg.tsp_vers = TSPVERSION; 302*fe3493caSbostic if (gethostname(hostname, sizeof (hostname))) { 303*fe3493caSbostic perror("gethostname"); 304*fe3493caSbostic goto bad; 305*fe3493caSbostic } 3061d873399Skarels (void) strncpy(msg.tsp_name, hostname, sizeof (hostname)); 3071d873399Skarels msg.tsp_seq = htons((u_short)0); 308*fe3493caSbostic msg.tsp_time.tv_sec = htonl((u_long)ntv.tv_sec); 309*fe3493caSbostic msg.tsp_time.tv_usec = htonl((u_long)ntv.tv_usec); 3101d873399Skarels length = sizeof (struct sockaddr_in); 3111d873399Skarels if (connect(s, &dest, length) < 0) { 3121d873399Skarels perror("date: connect"); 3131d873399Skarels goto bad; 3141d873399Skarels } 3153416d647Slepreau if (send(s, (char *)&msg, sizeof (struct tsp), 0) < 0) { 3161d873399Skarels if (errno != ECONNREFUSED) 3171d873399Skarels perror("date: send"); 3181d873399Skarels goto bad; 3191d873399Skarels } 3201d873399Skarels timed_ack = -1; 3211d873399Skarels waittime = WAITACK; 3221d873399Skarels loop: 3231d873399Skarels tout.tv_sec = waittime; 3241d873399Skarels tout.tv_usec = 0; 3251d873399Skarels FD_ZERO(&ready); 3261d873399Skarels FD_SET(s, &ready); 3271d873399Skarels found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); 3281d873399Skarels length = sizeof(err); 3293416d647Slepreau if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &length) == 0 3303416d647Slepreau && err) { 3311d873399Skarels errno = err; 3321d873399Skarels if (errno != ECONNREFUSED) 3331d873399Skarels perror("date: send (delayed error)"); 3341d873399Skarels goto bad; 3351d873399Skarels } 3361d873399Skarels if (found > 0 && FD_ISSET(s, &ready)) { 3371d873399Skarels length = sizeof (struct sockaddr_in); 3383416d647Slepreau if (recvfrom(s, (char *)&msg, sizeof (struct tsp), 0, &from, 3391d873399Skarels &length) < 0) { 3401d873399Skarels if (errno != ECONNREFUSED) 3411d873399Skarels perror("date: recvfrom"); 3421d873399Skarels goto bad; 3431d873399Skarels } 3441d873399Skarels msg.tsp_seq = ntohs(msg.tsp_seq); 3451d873399Skarels msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 3461d873399Skarels msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 3471d873399Skarels switch (msg.tsp_type) { 3481d873399Skarels 3491d873399Skarels case TSP_ACK: 3501d873399Skarels timed_ack = TSP_ACK; 3511d873399Skarels waittime = WAITDATEACK; 3521d873399Skarels goto loop; 3531d873399Skarels 3541d873399Skarels case TSP_DATEACK: 3553416d647Slepreau (void)close(s); 3561d873399Skarels return (1); 3571d873399Skarels 3581d873399Skarels default: 3591d873399Skarels fprintf(stderr, 3601d873399Skarels "date: Wrong ack received from timed: %s\n", 3611d873399Skarels tsptype[msg.tsp_type]); 3621d873399Skarels timed_ack = -1; 3631d873399Skarels break; 3641d873399Skarels } 3651d873399Skarels } 3661d873399Skarels if (timed_ack == -1) 367*fe3493caSbostic fputs("date: Can't reach time daemon, time set locally.\n", 368*fe3493caSbostic stderr); 3691d873399Skarels bad: 3703416d647Slepreau (void)close(s); 371a645e934Slepreau retval = 2; 3721d873399Skarels return (0); 3731d873399Skarels } 374