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: }

Defined functions

gtime defined in line 161; used 1 times
main defined in line 46; never used
netsettime defined in line 248; used 1 times

Defined variables

copyright defined in line 8; never used
dmsize defined in line 38; used 1 times
retval defined in line 36; used 6 times
sccsid defined in line 12; never used
tv defined in line 35; used 22 times
wtmp defined in line 41; used 4 times

Defined macros

ATOI2 defined in line 33; used 5 times
TSPTYPES defined in line 234; never used
WAITACK defined in line 237; used 1 times
WAITDATEACK defined in line 238; used 1 times
WTMP defined in line 32; used 1 times
Last modified: 1996-07-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4329
Valid CSS Valid XHTML 1.0 Strict