1ad4dcd8fSsam #ifndef lint 2*8df64c17Sgusella static char sccsid[] = "@(#)date.c 4.7 (Berkeley) 06/17/85"; 3*8df64c17Sgusella #endif not lint 4ad4dcd8fSsam 563fd2155Sbill /* 6a3ca036fSleres * Date - print and set date 7*8df64c17Sgusella * Modified by Riccardo Gusella to work with timed 863fd2155Sbill */ 9a3ca036fSleres 10*8df64c17Sgusella #include <sys/types.h> 11a3ca036fSleres #include <stdio.h> 1229f671e3Swnj #include <sys/time.h> 13*8df64c17Sgusella #include <sys/socket.h> 14*8df64c17Sgusella #include <netinet/in.h> 15*8df64c17Sgusella #include <netdb.h> 16*8df64c17Sgusella #define TSPTYPES 17*8df64c17Sgusella #include <protocols/timed.h> 18*8df64c17Sgusella #include <sys/file.h> 19*8df64c17Sgusella #include <errno.h> 20*8df64c17Sgusella #include <syslog.h> 2163fd2155Sbill #include <utmp.h> 22*8df64c17Sgusella 23a3ca036fSleres #define WTMP "/usr/adm/wtmp" 24ad4dcd8fSsam 25*8df64c17Sgusella struct timeval tv, now; 26ad4dcd8fSsam struct timezone tz; 2763fd2155Sbill char *ap, *ep, *sp; 2863fd2155Sbill int uflag; 2963fd2155Sbill 3063fd2155Sbill char *timezone(); 3163fd2155Sbill static int dmsize[12] = 32ad4dcd8fSsam { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 33a3ca036fSleres static char *usage = "usage: date [-u] [yymmddhhmm[.ss]]\n"; 3463fd2155Sbill 353ebd153dSsam struct utmp wtmp[2] = { 363ebd153dSsam { "|", "", "", 0 }, 373ebd153dSsam { "{", "", "", 0 } 383ebd153dSsam }; 3963fd2155Sbill 4063fd2155Sbill char *ctime(); 4163fd2155Sbill char *asctime(); 4263fd2155Sbill struct tm *localtime(); 4363fd2155Sbill struct tm *gmtime(); 4463fd2155Sbill 45*8df64c17Sgusella char *strcpy(); 46*8df64c17Sgusella char *username, *getlogin(); 47*8df64c17Sgusella 48*8df64c17Sgusella #define WAITACK 10 /* seconds */ 49*8df64c17Sgusella #define WAITDATEACK 5 /* seconds */ 50*8df64c17Sgusella 51*8df64c17Sgusella int sock, length, port; 52*8df64c17Sgusella int ready, found; 53*8df64c17Sgusella char hostname[32]; 54*8df64c17Sgusella struct timeval tout; 55*8df64c17Sgusella struct servent *srvp; 56*8df64c17Sgusella struct hostent *hp, *gethostbyname(); 57*8df64c17Sgusella struct tsp msg; 58*8df64c17Sgusella struct sockaddr_in sin, dest, from; 59*8df64c17Sgusella 6063fd2155Sbill main(argc, argv) 61ad4dcd8fSsam int argc; 6263fd2155Sbill char *argv[]; 6363fd2155Sbill { 64*8df64c17Sgusella int wf; 65*8df64c17Sgusella int timed_ack; 6663fd2155Sbill register char *tzn; 67*8df64c17Sgusella int bytenetorder(), bytehostorder(); 6863fd2155Sbill 69*8df64c17Sgusella (void) gettimeofday(&tv, &tz); 70*8df64c17Sgusella 71a3ca036fSleres if (argc > 1 && strcmp(argv[1], "-u") == 0) { 7263fd2155Sbill argc--; 7363fd2155Sbill argv++; 7463fd2155Sbill uflag++; 7563fd2155Sbill } 76*8df64c17Sgusella if (argc > 2) { 77*8df64c17Sgusella printf(usage); 78*8df64c17Sgusella exit(1); 79*8df64c17Sgusella } 80*8df64c17Sgusella if (argc == 1) 81*8df64c17Sgusella goto display; 82*8df64c17Sgusella 83*8df64c17Sgusella if (getuid() != 0) { 84*8df64c17Sgusella printf("You are not superuser: date not set\n"); 85*8df64c17Sgusella exit(1); 86*8df64c17Sgusella } 87*8df64c17Sgusella username = getlogin(); 88*8df64c17Sgusella if (username == NULL) { 89*8df64c17Sgusella printf("Cannot record your name: date not set\n"); 90*8df64c17Sgusella exit(1); 91*8df64c17Sgusella } 92*8df64c17Sgusella syslog(LOG_ERR, "date: set by %s", username); 93*8df64c17Sgusella 9463fd2155Sbill ap = argv[1]; 95c12caacaSralph wtmp[0].ut_time = tv.tv_sec; 9663fd2155Sbill if (gtime()) { 97a3ca036fSleres printf(usage); 9863fd2155Sbill exit(1); 9963fd2155Sbill } 10063fd2155Sbill /* convert to GMT assuming local time */ 10163fd2155Sbill if (uflag == 0) { 102ad4dcd8fSsam tv.tv_sec += (long)tz.tz_minuteswest*60; 10363fd2155Sbill /* now fix up local daylight time */ 104*8df64c17Sgusella if (localtime((long *)&tv.tv_sec)->tm_isdst) 105ad4dcd8fSsam tv.tv_sec -= 60*60; 10663fd2155Sbill } 107*8df64c17Sgusella (void) open("/etc/timed", O_WRONLY, 01700); 108*8df64c17Sgusella if (errno != ETXTBSY) { 109ad4dcd8fSsam if (settimeofday(&tv, (struct timezone *)0) < 0) { 110*8df64c17Sgusella perror("settimeofday"); 111*8df64c17Sgusella exit(1); 112*8df64c17Sgusella } 113*8df64c17Sgusella if ((wf = open(WTMP, 1)) >= 0) { 114*8df64c17Sgusella (void) time((long *)&wtmp[1].ut_time); 115*8df64c17Sgusella (void) lseek(wf, (off_t)0L, 2); 116*8df64c17Sgusella (void) write(wf, (char *)wtmp, sizeof(wtmp)); 117*8df64c17Sgusella (void) close(wf); 118*8df64c17Sgusella } 119*8df64c17Sgusella goto display; 120*8df64c17Sgusella } 121*8df64c17Sgusella 122*8df64c17Sgusella /* 123*8df64c17Sgusella * Here we set the date in the machines controlled by timedaemons 124*8df64c17Sgusella * by communicating the new date to the local timedaemon. 125*8df64c17Sgusella * If the timedaemon is in the master state, it performs the correction on 126*8df64c17Sgusella * all slaves. If it is in the slave state, it notifies the master 127*8df64c17Sgusella * that a correction is needed. 128*8df64c17Sgusella */ 129*8df64c17Sgusella 130*8df64c17Sgusella srvp = getservbyname("timed", "udp"); 131*8df64c17Sgusella if (srvp == 0) { 132*8df64c17Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 133*8df64c17Sgusella exit(1); 134*8df64c17Sgusella } 135*8df64c17Sgusella dest.sin_port = srvp->s_port; 136*8df64c17Sgusella dest.sin_family = AF_INET; 137*8df64c17Sgusella sock = socket(AF_INET, SOCK_DGRAM, 0); 138*8df64c17Sgusella if (sock < 0) { 139*8df64c17Sgusella perror("opening socket"); 140*8df64c17Sgusella exit(1); 141*8df64c17Sgusella } 142*8df64c17Sgusella 143*8df64c17Sgusella sin.sin_family = AF_INET; 144*8df64c17Sgusella for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 145*8df64c17Sgusella sin.sin_port = htons((u_short)port); 146*8df64c17Sgusella if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 147*8df64c17Sgusella break; 148*8df64c17Sgusella if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 149*8df64c17Sgusella perror("bind"); 150*8df64c17Sgusella (void) close(sock); 151*8df64c17Sgusella exit(1); 15263fd2155Sbill } 15363fd2155Sbill } 154*8df64c17Sgusella if (port == IPPORT_RESERVED / 2) { 155*8df64c17Sgusella fprintf(stderr, "socket: All ports in use\n"); 156*8df64c17Sgusella (void) close(sock); 157*8df64c17Sgusella exit(1); 158*8df64c17Sgusella } 159*8df64c17Sgusella 160*8df64c17Sgusella (void) gethostname(hostname,sizeof(hostname)); 161*8df64c17Sgusella hp = gethostbyname(hostname); 162*8df64c17Sgusella if (hp == NULL) { 163*8df64c17Sgusella perror("gethostbyname"); 164*8df64c17Sgusella exit(1); 165*8df64c17Sgusella } 166*8df64c17Sgusella bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 167*8df64c17Sgusella 168*8df64c17Sgusella msg.tsp_type = TSP_DATE; 169*8df64c17Sgusella (void) strcpy(msg.tsp_name, hostname); 170*8df64c17Sgusella (void) gettimeofday(&now, (struct timezone *)0); 171*8df64c17Sgusella timevalsub(&tv, &now); 172*8df64c17Sgusella msg.tsp_time = tv; 173*8df64c17Sgusella bytenetorder(&msg); 174*8df64c17Sgusella length = sizeof(struct sockaddr_in); 175*8df64c17Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 176*8df64c17Sgusella &dest, length) < 0) { 177*8df64c17Sgusella perror("sendto"); 178*8df64c17Sgusella exit(1); 179*8df64c17Sgusella } 180*8df64c17Sgusella 181*8df64c17Sgusella timed_ack = -1; 182*8df64c17Sgusella tout.tv_sec = WAITACK; 183*8df64c17Sgusella tout.tv_usec = 0; 184*8df64c17Sgusella loop: 185*8df64c17Sgusella ready = 1<<sock; 186*8df64c17Sgusella found = select(20, &ready, (int *)0, (int *)0, &tout); 187*8df64c17Sgusella if (found) { 188*8df64c17Sgusella length = sizeof(struct sockaddr_in); 189*8df64c17Sgusella if (recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 190*8df64c17Sgusella &from, &length) < 0) { 191*8df64c17Sgusella perror("recvfrom"); 192*8df64c17Sgusella exit(1); 193*8df64c17Sgusella } 194*8df64c17Sgusella bytehostorder(&msg); 195*8df64c17Sgusella 196*8df64c17Sgusella switch (msg.tsp_type) { 197*8df64c17Sgusella 198*8df64c17Sgusella case TSP_ACK: 199*8df64c17Sgusella timed_ack = TSP_ACK; 200*8df64c17Sgusella tout.tv_sec = WAITDATEACK; 201*8df64c17Sgusella tout.tv_usec = 0; 202*8df64c17Sgusella goto loop; 203*8df64c17Sgusella break; 204*8df64c17Sgusella case TSP_DATEACK: 205*8df64c17Sgusella goto display; 206*8df64c17Sgusella break; 207*8df64c17Sgusella default: 208*8df64c17Sgusella printf("Wrong ack received: %s\n", 209*8df64c17Sgusella tsptype[msg.tsp_type]); 210*8df64c17Sgusella timed_ack = -1; 211*8df64c17Sgusella break; 212*8df64c17Sgusella } 213*8df64c17Sgusella } 214*8df64c17Sgusella 215*8df64c17Sgusella if (timed_ack == TSP_ACK) { 216*8df64c17Sgusella printf("Network date being set\n"); 217*8df64c17Sgusella exit(0); 218*8df64c17Sgusella } else { 219*8df64c17Sgusella printf("Communication problems\n"); 220*8df64c17Sgusella exit(1); 221*8df64c17Sgusella } 222*8df64c17Sgusella 223*8df64c17Sgusella display: 224*8df64c17Sgusella (void) gettimeofday(&tv, (struct timezone *)0); 22563fd2155Sbill if (uflag) { 226*8df64c17Sgusella ap = asctime(gmtime((long *)&tv.tv_sec)); 22763fd2155Sbill tzn = "GMT"; 22863fd2155Sbill } else { 22963fd2155Sbill struct tm *tp; 230*8df64c17Sgusella tp = localtime((long *)&tv.tv_sec); 23163fd2155Sbill ap = asctime(tp); 232ad4dcd8fSsam tzn = timezone(tz.tz_minuteswest, tp->tm_isdst); 23363fd2155Sbill } 23463fd2155Sbill printf("%.20s", ap); 23563fd2155Sbill if (tzn) 23663fd2155Sbill printf("%s", tzn); 23763fd2155Sbill printf("%s", ap+19); 23863fd2155Sbill } 23963fd2155Sbill 24063fd2155Sbill gtime() 24163fd2155Sbill { 24263fd2155Sbill register int i, year, month; 24363fd2155Sbill int day, hour, mins, secs; 24463fd2155Sbill struct tm *L; 24563fd2155Sbill char x; 24663fd2155Sbill 24763fd2155Sbill ep = ap; 24863fd2155Sbill while(*ep) ep++; 24963fd2155Sbill sp = ap; 25063fd2155Sbill while(sp < ep) { 25163fd2155Sbill x = *sp; 25263fd2155Sbill *sp++ = *--ep; 25363fd2155Sbill *ep = x; 25463fd2155Sbill } 25563fd2155Sbill sp = ap; 256*8df64c17Sgusella (void) gettimeofday(&tv, (struct timezone *)0); 257*8df64c17Sgusella L = localtime((long *)&tv.tv_sec); 25863fd2155Sbill secs = gp(-1); 25963fd2155Sbill if (*sp != '.') { 26063fd2155Sbill mins = secs; 26163fd2155Sbill secs = 0; 262a3ca036fSleres } else { 263a3ca036fSleres sp++; 26463fd2155Sbill mins = gp(-1); 26563fd2155Sbill } 26663fd2155Sbill hour = gp(-1); 26763fd2155Sbill day = gp(L->tm_mday); 26863fd2155Sbill month = gp(L->tm_mon+1); 26963fd2155Sbill year = gp(L->tm_year); 27063fd2155Sbill if (*sp) 27163fd2155Sbill return (1); 27263fd2155Sbill if (month < 1 || month > 12 || 27363fd2155Sbill day < 1 || day > 31 || 27463fd2155Sbill mins < 0 || mins > 59 || 27563fd2155Sbill secs < 0 || secs > 59) 27663fd2155Sbill return (1); 27763fd2155Sbill if (hour == 24) { 278a3ca036fSleres hour = 0; 279a3ca036fSleres day++; 28063fd2155Sbill } 28163fd2155Sbill if (hour < 0 || hour > 23) 28263fd2155Sbill return (1); 283ad4dcd8fSsam tv.tv_sec = 0; 28463fd2155Sbill year += 1900; 28563fd2155Sbill for (i = 1970; i < year; i++) 286ad4dcd8fSsam tv.tv_sec += dysize(i); 28763fd2155Sbill /* Leap year */ 28863fd2155Sbill if (dysize(year) == 366 && month >= 3) 289ad4dcd8fSsam tv.tv_sec++; 29063fd2155Sbill while (--month) 291ad4dcd8fSsam tv.tv_sec += dmsize[month-1]; 292ad4dcd8fSsam tv.tv_sec += day-1; 293ad4dcd8fSsam tv.tv_sec = 24*tv.tv_sec + hour; 294ad4dcd8fSsam tv.tv_sec = 60*tv.tv_sec + mins; 295ad4dcd8fSsam tv.tv_sec = 60*tv.tv_sec + secs; 29663fd2155Sbill return (0); 29763fd2155Sbill } 29863fd2155Sbill 29963fd2155Sbill gp(dfault) 30063fd2155Sbill { 30163fd2155Sbill register int c, d; 30263fd2155Sbill 30363fd2155Sbill if (*sp == 0) 30463fd2155Sbill return (dfault); 30563fd2155Sbill c = (*sp++) - '0'; 30663fd2155Sbill d = (*sp ? (*sp++) - '0' : 0); 30763fd2155Sbill if (c < 0 || c > 9 || d < 0 || d > 9) 30863fd2155Sbill return (-1); 30963fd2155Sbill return (c+10*d); 31063fd2155Sbill } 311*8df64c17Sgusella 312*8df64c17Sgusella timevalsub(t1, t2) 313*8df64c17Sgusella struct timeval *t1, *t2; 314*8df64c17Sgusella { 315*8df64c17Sgusella t1->tv_sec -= t2->tv_sec; 316*8df64c17Sgusella t1->tv_usec -= t2->tv_usec; 317*8df64c17Sgusella if (t1->tv_usec < 0) { 318*8df64c17Sgusella t1->tv_sec--; 319*8df64c17Sgusella t1->tv_usec += 1000000; 320*8df64c17Sgusella } 321*8df64c17Sgusella if (t1->tv_usec >= 1000000) { 322*8df64c17Sgusella t1->tv_sec++; 323*8df64c17Sgusella t1->tv_usec -= 1000000; 324*8df64c17Sgusella } 325*8df64c17Sgusella } 326*8df64c17Sgusella 327*8df64c17Sgusella bytenetorder(ptr) 328*8df64c17Sgusella struct tsp *ptr; 329*8df64c17Sgusella { 330*8df64c17Sgusella ptr->tsp_seq = htons((u_short)ptr->tsp_seq); 331*8df64c17Sgusella ptr->tsp_time.tv_sec = htonl((u_long)ptr->tsp_time.tv_sec); 332*8df64c17Sgusella ptr->tsp_time.tv_usec = htonl((u_long)ptr->tsp_time.tv_usec); 333*8df64c17Sgusella } 334*8df64c17Sgusella 335*8df64c17Sgusella bytehostorder(ptr) 336*8df64c17Sgusella struct tsp *ptr; 337*8df64c17Sgusella { 338*8df64c17Sgusella ptr->tsp_seq = ntohs((u_short)ptr->tsp_seq); 339*8df64c17Sgusella ptr->tsp_time.tv_sec = ntohl((u_long)ptr->tsp_time.tv_sec); 340*8df64c17Sgusella ptr->tsp_time.tv_usec = ntohl((u_long)ptr->tsp_time.tv_usec); 341*8df64c17Sgusella } 342