386BSD 0.1 development
[unix-history] / usr / src / bin / date / date.c
index 3fcf7e5..0c57318 100644 (file)
-#ifndef lint
-static char sccsid[] = "@(#)date.c     4.10 (Berkeley) %G%";
-#endif not lint
-
 /*
 /*
- * Date - print and set date
- * Modified by Riccardo Gusella to work with timed 
+ * Copyright (c) 1985, 1987, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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
+char copyright[] =
+"@(#) Copyright (c) 1985, 1987, 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)date.c     5.5 (Berkeley) 3/18/91";
+#endif /* not lint */
+
 #include <sys/param.h>
 #include <sys/param.h>
-#include <stdio.h>
 #include <sys/time.h>
 #include <sys/time.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#define TSPTYPES
-#include <protocols/timed.h>
 #include <sys/file.h>
 #include <sys/file.h>
-#include <errno.h>
 #include <syslog.h>
 #include <syslog.h>
-#include <utmp.h>
-
-#define WTMP "/usr/adm/wtmp"
-#define WAITACK                2       /* seconds */
-#define WAITDATEACK    5       /* seconds */
-
-struct timeval tv, now;
-struct timezone tz;
-char   *ap, *ep, *sp;
-int    uflag;
-
-char   *timezone();
-static int     dmsize[12] =
-    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-static char *usage = "usage: date [-u] [yymmddhhmm[.ss]]\n";
-
-struct utmp wtmp[2] = {
-       { "|", "", "", 0 },
-       { "{", "", "", 0 }
-};
-
-char   *ctime();
-char   *asctime();
-struct tm *localtime();
-struct tm *gmtime();
-
-char *strcpy();
-char *username, *getlogin();
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 
 
-int sock, length, port;
-char hostname[MAXHOSTNAMELEN];
-struct timeval tout;
-struct servent *srvp;
-struct tsp msg;
-struct sockaddr_in sin, dest, from;
+time_t tval;
+int retval, nflag;
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
-       char *argv[];
+       char **argv;
 {
 {
-       int wf;
-       int timed_ack, found;
-       long waittime;
-       register char *tzn;
-       fd_set ready;
-       extern int errno;
-       int bytenetorder(), bytehostorder();
-
-       (void) gettimeofday(&tv, &tz);
-       now = tv;
-
-       if (argc > 1 && strcmp(argv[1], "-u") == 0) {
-               argc--;
-               argv++;
-               uflag++;
-       }
-       if (argc > 2) {
-               printf(usage);
-               exit(1);
-       }
-       if (argc == 1) 
-               goto display;
-
-       if (getuid() != 0) {
-               printf("You are not superuser: date not set\n");
-               goto display;
-       }
-       username = getlogin();
-       if (username == NULL)           /* single-user or no tty */
-               username = "root";
-       syslog(LOG_SECURITY, "date: set by %s", username);
-
-       ap = argv[1];
-       wtmp[0].ut_time = tv.tv_sec;
-       if (gtime()) {
-               printf(usage);
-               goto display;
-       }
-       /* convert to GMT assuming local time */
-       if (uflag == 0) {
-               tv.tv_sec += (long)tz.tz_minuteswest*60;
-               /* now fix up local daylight time */
-               if (localtime((time_t *)&tv.tv_sec)->tm_isdst)
-                       tv.tv_sec -= 60*60;
-       }
-       
-/*
- * Here we 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.
- */
-
-       srvp = getservbyname("timed", "udp");
-       if (srvp == 0) {
-               fprintf(stderr, "udp/timed: unknown service\n");
-               goto oldway;
-       }       
-       dest.sin_port = srvp->s_port;
-       dest.sin_family = AF_INET;
-       dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
-       sock = socket(AF_INET, SOCK_DGRAM, 0);
-       if (sock < 0) {
-               if (errno != EPROTONOSUPPORT)
-                       perror("socket");
-               goto oldway;
-       }
-
-       sin.sin_family = AF_INET;
-       for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
-               sin.sin_port = htons((u_short)port);
-               if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+       extern int optind;
+       extern char *optarg;
+       struct timezone tz;
+       int ch, rflag;
+       char *format, buf[1024];
+
+       tz.tz_dsttime = tz.tz_minuteswest = 0;
+       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;
                        break;
                        break;
-               if (errno != EADDRINUSE) {
-                       perror("bind");
-                       (void) close(sock);
-                       goto oldway;
-               }
-       }
-       if (port == IPPORT_RESERVED / 2) {
-               fprintf(stderr, "socket: All ports in use\n");
-               (void) close(sock);
-               goto oldway;
-       }
-
-       msg.tsp_type = TSP_DATE;
-       msg.tsp_vers = TSPVERSION;
-       (void) gethostname(hostname, sizeof(hostname));
-       (void) strcpy(msg.tsp_name, hostname);
-       msg.tsp_time = tv;
-       timevalsub(&msg.tsp_time, &now);
-       bytenetorder(&msg);
-       length = sizeof(struct sockaddr_in);
-       if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 
-                                               &dest, length) < 0) {
-               if (errno != ECONNREFUSED)
-                       perror("sendto");
-               goto oldway;
-       }
-
-       timed_ack = -1;
-       waittime = WAITACK;
-loop:
-       tout.tv_sec = waittime;
-       tout.tv_usec = 0;
-       FD_ZERO(&ready);
-       FD_SET(sock, &ready);
-       found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
-       if (found > 0 && FD_ISSET(sock, &ready)) {
-               length = sizeof(struct sockaddr_in);
-               if (recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 
-                                                       &from, &length) < 0) {
-                       perror("recvfrom");
-                       goto oldway;
-               }
-               bytehostorder(&msg);
-
-               switch (msg.tsp_type) {
-
-               case TSP_ACK:
-                       timed_ack = TSP_ACK;
-                       waittime = WAITDATEACK;
-                       goto loop;
-               case TSP_DATEACK:
-                       goto display;
-               default:
-                       printf("Wrong ack received from timed: %s\n", 
-                                               tsptype[msg.tsp_type]);
-                       timed_ack = -1;
+               case 'n':               /* don't set network */
+                       nflag = 1;
                        break;
                        break;
+               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 */
+                                       /* error check; don't allow "PST" */
+                       if (isdigit(*optarg)) {
+                               tz.tz_minuteswest = atoi(optarg);
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       usage();
                }
                }
+       argc -= optind;
+       argv += optind;
+
+       /*
+        * 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 (timed_ack == TSP_ACK)
-               printf("Network date being set\n");
-       else {
-               printf("Communication error with timed\n");
-oldway:
-               if (settimeofday(&tv, (struct timezone *)0) < 0) {
-                       perror("settimeofday");
-                       goto display;
-               }
-               if ((wf = open(WTMP, 1)) >= 0) {
-                       (void) time((time_t *)&wtmp[1].ut_time);
-                       (void) lseek(wf, (off_t)0L, 2);
-                       (void) write(wf, (char *)wtmp, sizeof(wtmp));
-                       (void) close(wf);
-               }
-       }
-
-display:
-       (void) gettimeofday(&tv, (struct timezone *)0);
-       if (uflag) {
-               ap = asctime(gmtime((time_t *)&tv.tv_sec));
-               tzn = "GMT";
-       } else {
-               struct tm *tp;
-               tp = localtime((time_t *)&tv.tv_sec);
-               ap = asctime(tp);
-               tzn = timezone(tz.tz_minuteswest, tp->tm_isdst);
+       if (!rflag && time(&tval) == -1) {
+               perror("date: time");
+               exit(1);
        }
        }
-       printf("%.20s", ap);
-       if (tzn)
-               printf("%s", tzn);
-       printf("%s", ap+19);
-}
 
 
-gtime()
-{
-       register int i, year, month;
-       int day, hour, mins, secs;
-       struct tm *L;
-       char x;
+       format = "%a %b %e %H:%M:%S %Z %Y\n";
 
 
-       ep = ap;
-       while(*ep) ep++;
-       sp = ap;
-       while(sp < ep) {
-               x = *sp;
-               *sp++ = *--ep;
-               *ep = x;
-       }
-       sp = ap;
-       (void) gettimeofday(&tv, (struct timezone *)0);
-       L = localtime((time_t *)&tv.tv_sec);
-       secs = gp(-1);
-       if (*sp != '.') {
-               mins = secs;
-               secs = 0;
-       } else {
-               sp++;
-               mins = gp(-1);
+       /* allow the operands in any order */
+       if (*argv && **argv == '+') {
+               format = *argv + 1;
+               ++argv;
        }
        }
-       hour = gp(-1);
-       day = gp(L->tm_mday);
-       month = gp(L->tm_mon+1);
-       year = gp(L->tm_year);
-       if (*sp)
-               return (1);
-       if (month < 1 || month > 12 ||
-           day < 1 || day > 31 ||
-           mins < 0 || mins > 59 ||
-           secs < 0 || secs > 59)
-               return (1);
-       if (hour == 24) {
-               hour = 0;
-               day++;
+
+       if (*argv) {
+               setthetime(*argv);
+               ++argv;
        }
        }
-       if (hour < 0 || hour > 23)
-               return (1);
-       tv.tv_sec = 0;
-       year += 1900;
-       for (i = 1970; i < year; i++)
-               tv.tv_sec += dysize(i);
-       /* Leap year */
-       if (dysize(year) == 366 && month >= 3)
-               tv.tv_sec++;
-       while (--month)
-               tv.tv_sec += dmsize[month-1];
-       tv.tv_sec += day-1;
-       tv.tv_sec = 24*tv.tv_sec + hour;
-       tv.tv_sec = 60*tv.tv_sec + mins;
-       tv.tv_sec = 60*tv.tv_sec + secs;
-       return (0);
-}
 
 
-gp(dfault)
-{
-       register int c, d;
+       if (*argv && **argv == '+')
+               format = *argv + 1;
 
 
-       if (*sp == 0)
-               return (dfault);
-       c = (*sp++) - '0';
-       d = (*sp ? (*sp++) - '0' : 0);
-       if (c < 0 || c > 9 || d < 0 || d > 9)
-               return (-1);
-       return (c+10*d);
+       (void)strftime(buf, sizeof(buf), format, localtime(&tval));
+       (void)printf("%s", buf);
+       exit(retval);
 }
 
 }
 
-timevalsub(t1, t2)
-struct timeval *t1, *t2;
+#define        ATOI2(ar)       ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+setthetime(p)
+       register char *p;
 {
 {
-       t1->tv_sec -= t2->tv_sec;
-       t1->tv_usec -= t2->tv_usec;
-       if (t1->tv_usec < 0) {
-               t1->tv_sec--;
-               t1->tv_usec += 1000000;
-       }
-       if (t1->tv_usec >= 1000000) {
-               t1->tv_sec++;
-               t1->tv_usec -= 1000000;
+       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);
+               }
+               logwtmp("{", "date", "");
        }
 }
 
        }
 }
 
-bytenetorder(ptr)
-struct tsp *ptr;
+badformat()
 {
 {
-       ptr->tsp_seq = htons((u_short)ptr->tsp_seq);
-       ptr->tsp_time.tv_sec = htonl((u_long)ptr->tsp_time.tv_sec);
-       ptr->tsp_time.tv_usec = htonl((u_long)ptr->tsp_time.tv_usec);
+       (void)fprintf(stderr, "date: illegal time format.\n");
+       usage();
 }
 
 }
 
-bytehostorder(ptr)
-struct tsp *ptr;
+usage()
 {
 {
-       ptr->tsp_seq = ntohs((u_short)ptr->tsp_seq);
-       ptr->tsp_time.tv_sec = ntohl((u_long)ptr->tsp_time.tv_sec);
-       ptr->tsp_time.tv_usec = ntohl((u_long)ptr->tsp_time.tv_usec);
+       (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);
 }
 }