BSD 4_3_Net_2 release
[unix-history] / usr / src / bin / date / date.c
index 0a8ed60..0c57318 100644 (file)
@@ -2,19 +2,33 @@
  * Copyright (c) 1985, 1987, 1988 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1985, 1987, 1988 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement:  ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
@@ -24,31 +38,21 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)date.c     4.27 (Berkeley) 5/31/90";
+static char sccsid[] = "@(#)date.c     5.5 (Berkeley) 3/18/91";
 #endif /* not lint */
 
 #endif /* not lint */
 
-/*
- * Date - print and set date
- */
-
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/file.h>
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/file.h>
-#include <errno.h>
 #include <syslog.h>
 #include <syslog.h>
-#include <utmp.h>
-#include <tzfile.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <ctype.h>
+#include <stdlib.h>
 #include <string.h>
 #include <string.h>
+#include <ctype.h>
 
 
-#define        ATOI2(ar)       (ar[0] - '0') * 10 + (ar[1] - '0'); ar += 2;
-
-static struct timeval  tv;
-static int     retval;
-
-static int     dmsize[] =
-       { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+time_t tval;
+int retval, nflag;
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
@@ -57,14 +61,12 @@ main(argc, argv)
        extern int optind;
        extern char *optarg;
        struct timezone tz;
        extern int optind;
        extern char *optarg;
        struct timezone tz;
-       char *ap, *tzn;
-       int ch, uflag, nflag;
-       char *username, *getlogin();
-       time_t time();
+       int ch, rflag;
+       char *format, buf[1024];
 
 
-       nflag = uflag = 0;
        tz.tz_dsttime = tz.tz_minuteswest = 0;
        tz.tz_dsttime = tz.tz_minuteswest = 0;
-       while ((ch = getopt(argc, argv, "d:nut:")) != EOF)
+       rflag = 0;
+       while ((ch = getopt(argc, argv, "d:nr:ut:")) != EOF)
                switch((char)ch) {
                case 'd':               /* daylight savings time */
                        tz.tz_dsttime = atoi(optarg) ? 1 : 0;
                switch((char)ch) {
                case 'd':               /* daylight savings time */
                        tz.tz_dsttime = atoi(optarg) ? 1 : 0;
@@ -72,289 +74,150 @@ main(argc, argv)
                case 'n':               /* don't set network */
                        nflag = 1;
                        break;
                case 'n':               /* don't set network */
                        nflag = 1;
                        break;
-               case 'u':               /* do it in GMT */
-                       uflag = 1;
+               case 'r':               /* user specified seconds */
+                       rflag = 1;
+                       tval = atol(optarg);
+                       break;
+               case 'u':               /* do everything in GMT */
+                       (void)setenv("TZ", "GMT0", 1);
                        break;
                case 't':               /* minutes west of GMT */
                        break;
                case 't':               /* minutes west of GMT */
-                                       /* error check; we can't allow "PST" */
+                                       /* error check; don't allow "PST" */
                        if (isdigit(*optarg)) {
                                tz.tz_minuteswest = atoi(optarg);
                                break;
                        }
                        if (isdigit(*optarg)) {
                                tz.tz_minuteswest = atoi(optarg);
                                break;
                        }
-                       /*FALLTHROUGH*/
+                       /* FALLTHROUGH */
                default:
                        usage();
                default:
                        usage();
-                       exit(1);
                }
        argc -= optind;
        argv += optind;
 
                }
        argc -= optind;
        argv += optind;
 
-       if (argc > 1) {
-               usage();
-               exit(1);
-       }
-
+       /*
+        * If -d or -t, set the timezone or daylight savings time; this
+        * doesn't belong here, there kernel should not know about either.
+        */
        if ((tz.tz_minuteswest || tz.tz_dsttime) &&
            settimeofday((struct timeval *)NULL, &tz)) {
                perror("date: settimeofday");
                exit(1);
        }
 
        if ((tz.tz_minuteswest || tz.tz_dsttime) &&
            settimeofday((struct timeval *)NULL, &tz)) {
                perror("date: settimeofday");
                exit(1);
        }
 
-       if (gettimeofday(&tv, &tz)) {
-               perror("date: gettimeofday");
+       if (!rflag && time(&tval) == -1) {
+               perror("date: time");
                exit(1);
        }
 
                exit(1);
        }
 
-       if (!argc)
-               goto display;
+       format = "%a %b %e %H:%M:%S %Z %Y\n";
 
 
-       if (gtime(*argv)) {
-               usage();
-               exit(1);
+       /* allow the operands in any order */
+       if (*argv && **argv == '+') {
+               format = *argv + 1;
+               ++argv;
        }
 
        }
 
-       if (!uflag) {           /* convert to GMT assuming local time */
-               tv.tv_sec += (long)tz.tz_minuteswest * SECSPERMIN;
-                               /* now fix up local daylight time */
-               if (localtime((time_t *)&tv.tv_sec)->tm_isdst)
-                       tv.tv_sec -= SECSPERHOUR;
-       }
-       if (nflag || !netsettime(tv)) {
-               logwtmp("|", "date", "");
-               if (settimeofday(&tv, (struct timezone *)NULL)) {
-                       perror("date: settimeofday");
-                       exit(1);
-               }
-               logwtmp("{", "date", "");
+       if (*argv) {
+               setthetime(*argv);
+               ++argv;
        }
 
        }
 
-       username = getlogin();
-       if (!username || *username == '\0')     /* single-user or no tty */
-               username = "root";
-       syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", username);
-
-display:
-       if (gettimeofday(&tv, (struct timezone *)NULL)) {
-               perror("date: gettimeofday");
-               exit(1);
-       }
-       if (uflag) {
-               ap = asctime(gmtime((time_t *)&tv.tv_sec));
-               tzn = "GMT";
-       }
-       else {
-               struct tm *tp;
+       if (*argv && **argv == '+')
+               format = *argv + 1;
 
 
-               tp = localtime((time_t *)&tv.tv_sec);
-               ap = asctime(tp);
-               tzn = tp->tm_zone;
-       }
-       printf("%.20s%s%s", ap, tzn, ap + 19);
+       (void)strftime(buf, sizeof(buf), format, localtime(&tval));
+       (void)printf("%s", buf);
        exit(retval);
 }
 
        exit(retval);
 }
 
-/*
- * gtime --
- *     convert user's time into number of seconds
- */
-static
-gtime(ap)
-       register char *ap;
+#define        ATOI2(ar)       ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+setthetime(p)
+       register char *p;
 {
 {
-       register int year, month;
-       register char *C;
-       struct tm *L;
-       int day, hour, mins, secs;
-
-       for (secs = 0, C = ap; *C; ++C) {
-               if (*C == '.') {                /* seconds provided */
-                       if (strlen(C) != 3)
-                               return(1);
-                       *C = NULL;
-                       secs = (C[1] - '0') * 10 + (C[2] - '0');
-                       break;
+       register struct tm *lt;
+       struct timeval tv;
+       int dot;
+       char *t;
+
+       for (t = p, dot = 0; *t; ++t)
+               if (!isdigit(*t) && (*t != '.' || dot++))
+                       badformat();
+
+       lt = localtime(&tval);
+
+       if (t = index(p, '.')) {                /* .ss */
+               *t++ = '\0';
+               if (lt->tm_sec > 61)
+                       badformat();
+       } else
+               lt->tm_sec = 0;
+
+       for (t = p; *t; ++t)
+               if (!isdigit(*t))
+                       badformat();
+
+       switch (strlen(p)) {
+       case 10:                                /* yy */
+               lt->tm_year = ATOI2(p);
+               if (lt->tm_year < 69)           /* hack for 2000 ;-} */
+                       lt->tm_year += 100;
+               /* FALLTHROUGH */
+       case 8:                                 /* mm */
+               lt->tm_mon = ATOI2(p);
+               if (lt->tm_mon > 12)
+                       badformat();
+               --lt->tm_mon;                   /* time struct is 0 - 11 */
+               /* FALLTHROUGH */
+       case 6:                                 /* dd */
+               lt->tm_mday = ATOI2(p);
+               if (lt->tm_mday > 31)
+                       badformat();
+               /* FALLTHROUGH */
+       case 4:                                 /* hh */
+               lt->tm_hour = ATOI2(p);
+               if (lt->tm_hour > 23)
+                       badformat();
+               /* FALLTHROUGH */
+       case 2:                                 /* mm */
+               lt->tm_min = ATOI2(p);
+               if (lt->tm_min > 59)
+                       badformat();
+               break;
+       default:
+               badformat();
+       }
+
+       /* convert broken-down time to GMT clock time */
+       if ((tval = mktime(lt)) == -1)
+               badformat();
+
+       if (!(p = getlogin()))                  /* single-user or no tty */
+               p = "root";
+       syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
+
+       /* set the time */
+       if (nflag || netsettime(tval)) {
+               logwtmp("|", "date", "");
+               tv.tv_sec = tval;
+               tv.tv_usec = 0;
+               if (settimeofday(&tv, (struct timezone *)NULL)) {
+                       perror("date: settimeofday");
+                       exit(1);
                }
                }
-               if (!isdigit(*C))
-                       return(-1);
-       }
-
-       L = localtime((time_t *)&tv.tv_sec);
-       year = L->tm_year;                      /* defaults */
-       month = L->tm_mon + 1;
-       day = L->tm_mday;
-
-       switch ((int)(C - ap)) {                /* length */
-               case 10:                        /* yymmddhhmm */
-                       year = ATOI2(ap);
-               case 8:                         /* mmddhhmm */
-                       month = ATOI2(ap);
-               case 6:                         /* ddhhmm */
-                       day = ATOI2(ap);
-               case 4:                         /* hhmm */
-                       hour = ATOI2(ap);
-                       mins = ATOI2(ap);
-                       break;
-               default:
-                       return(1);
+               logwtmp("{", "date", "");
        }
        }
-
-       if (*ap || month < 1 || month > 12 || day < 1 || day > 31 ||
-            hour < 0 || hour > 23 || mins < 0 || mins > 59 ||
-            secs < 0 || secs > 59)
-               return(1);
-
-       tv.tv_sec = 0;
-       year += TM_YEAR_BASE;
-       if (isleap(year) && month > 2)
-               ++tv.tv_sec;
-       for (--year;year >= EPOCH_YEAR;--year)
-               tv.tv_sec += isleap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
-       while (--month)
-               tv.tv_sec += dmsize[month];
-       tv.tv_sec += day - 1;
-       tv.tv_sec = HOURSPERDAY * tv.tv_sec + hour;
-       tv.tv_sec = MINSPERHOUR * tv.tv_sec + mins;
-       tv.tv_sec = SECSPERMIN * tv.tv_sec + secs;
-       return(0);
 }
 
 }
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#define TSPTYPES
-#include <protocols/timed.h>
-
-#define        WAITACK         2       /* seconds */
-#define        WAITDATEACK     5       /* seconds */
-
-extern int errno;
-/*
- * Set the date in the machines controlled by timedaemons
- * by communicating the new date to the local timedaemon. 
- * If the timedaemon is in the master state, it performs the
- * correction on all slaves.  If it is in the slave state, it
- * notifies the master that a correction is needed.
- * Returns 1 on success, 0 on failure.
- */
-netsettime(ntv)
-       struct timeval ntv;
+badformat()
 {
 {
-       int s, length, port, timed_ack, found, err;
-       long waittime;
-       fd_set ready;
-       char hostname[MAXHOSTNAMELEN];
-       struct timeval tout;
-       struct servent *sp;
-       struct tsp msg;
-       struct sockaddr_in sin, dest, from;
-
-       sp = getservbyname("timed", "udp");
-       if (sp == 0) {
-               fputs("udp/timed: unknown service\n", stderr);
-               retval = 2;
-               return (0);
-       }
-       dest.sin_port = sp->s_port;
-       dest.sin_family = AF_INET;
-       dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
-       s = socket(AF_INET, SOCK_DGRAM, 0);
-       if (s < 0) {
-               if (errno != EPROTONOSUPPORT)
-                       perror("date: socket");
-               goto bad;
-       }
-       bzero((char *)&sin, sizeof (sin));
-       sin.sin_family = AF_INET;
-       for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
-               sin.sin_port = htons((u_short)port);
-               if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
-                       break;
-               if (errno != EADDRINUSE) {
-                       if (errno != EADDRNOTAVAIL)
-                               perror("date: bind");
-                       goto bad;
-               }
-       }
-       if (port == IPPORT_RESERVED / 2) {
-               fputs("date: All ports in use\n", stderr);
-               goto bad;
-       }
-       msg.tsp_type = TSP_SETDATE;
-       msg.tsp_vers = TSPVERSION;
-       if (gethostname(hostname, sizeof (hostname))) {
-               perror("date: gethostname");
-               goto bad;
-       }
-       (void) strncpy(msg.tsp_name, hostname, sizeof (hostname));
-       msg.tsp_seq = htons((u_short)0);
-       msg.tsp_time.tv_sec = htonl((u_long)ntv.tv_sec);
-       msg.tsp_time.tv_usec = htonl((u_long)ntv.tv_usec);
-       length = sizeof (struct sockaddr_in);
-       if (connect(s, &dest, length) < 0) {
-               perror("date: connect");
-               goto bad;
-       }
-       if (send(s, (char *)&msg, sizeof (struct tsp), 0) < 0) {
-               if (errno != ECONNREFUSED)
-                       perror("date: send");
-               goto bad;
-       }
-       timed_ack = -1;
-       waittime = WAITACK;
-loop:
-       tout.tv_sec = waittime;
-       tout.tv_usec = 0;
-       FD_ZERO(&ready);
-       FD_SET(s, &ready);
-       found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
-       length = sizeof(err);
-       if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &length) == 0
-           && err) {
-               errno = err;
-               if (errno != ECONNREFUSED)
-                       perror("date: send (delayed error)");
-               goto bad;
-       }
-       if (found > 0 && FD_ISSET(s, &ready)) {
-               length = sizeof (struct sockaddr_in);
-               if (recvfrom(s, (char *)&msg, sizeof (struct tsp), 0, &from,
-                   &length) < 0) {
-                       if (errno != ECONNREFUSED)
-                               perror("date: recvfrom");
-                       goto bad;
-               }
-               msg.tsp_seq = ntohs(msg.tsp_seq);
-               msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
-               msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
-               switch (msg.tsp_type) {
-
-               case TSP_ACK:
-                       timed_ack = TSP_ACK;
-                       waittime = WAITDATEACK;
-                       goto loop;
-
-               case TSP_DATEACK:
-                       (void)close(s);
-                       return (1);
-
-               default:
-                       fprintf(stderr,
-                           "date: Wrong ack received from timed: %s\n", 
-                           tsptype[msg.tsp_type]);
-                       timed_ack = -1;
-                       break;
-               }
-       }
-       if (timed_ack == -1)
-               fputs("date: Can't reach time daemon, time set locally.\n",
-                   stderr);
-bad:
-       (void)close(s);
-       retval = 2;
-       return (0);
+       (void)fprintf(stderr, "date: illegal time format.\n");
+       usage();
 }
 
 usage()
 {
 }
 
 usage()
 {
-       fputs("usage: date [-nu] [-d dst] [-t minutes_west] [yymmddhhmm[.ss]]\n", stderr);
+       (void)fprintf(stderr,
+           "usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]\n");
+       (void)fprintf(stderr, "            [yy[mm[dd[hh]]]]mm[.ss]]\n");
+       exit(1);
 }
 }