386BSD 0.1 development
[unix-history] / usr / src / bin / date / date.c
index 241251c..0c57318 100644 (file)
-#ifndef lint
-static char *sccsid = "@(#)date.c      4.7 (Berkeley) %G%";
-#endif
-
 /*
 /*
- * Date - print and set date
+ * 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.
  */
 
  */
 
-#include <stdio.h>
-#include <sys/time.h>
-#include <utmp.h>
-#define WTMP "/usr/adm/wtmp"
-
-struct timeval tv;
-struct timezone tz;
-char   *ap, *ep, *sp;
-int    uflag;
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1985, 1987, 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
 
 
-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";
+#ifndef lint
+static char sccsid[] = "@(#)date.c     5.5 (Berkeley) 3/18/91";
+#endif /* not lint */
 
 
-struct utmp wtmp[2] = {
-       { "|", "", "", 0 },
-       { "{", "", "", 0 }
-};
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 
 
-char   *ctime();
-char   *asctime();
-struct tm *localtime();
-struct tm *gmtime();
+time_t tval;
+int retval, nflag;
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
-       char *argv[];
+       char **argv;
 {
 {
-       register char *tzn;
-       int wf, rc;
-
-       rc = 0;
-       gettimeofday(&tv, &tz);
-       if (argc > 1 && strcmp(argv[1], "-u") == 0) {
-               argc--;
-               argv++;
-               uflag++;
-       }
-       if (argc > 1) {
-               ap = argv[1];
-               wtmp[0].ut_time = tv.tv_sec;
-               if (gtime()) {
-                       printf(usage);
-                       exit(1);
-               }
-               /* 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(&tv.tv_sec)->tm_isdst)
-                               tv.tv_sec -= 60*60;
-               }
-               tv.tv_sec = tv.tv_sec;
-               if (settimeofday(&tv, (struct timezone *)0) < 0) {
-                       rc++;
-                       perror("Failed to set date");
-               } else if ((wf = open(WTMP, 1)) >= 0) {
-                       time(&wtmp[1].ut_time);
-                       lseek(wf, 0L, 2);
-                       write(wf, (char *)wtmp, sizeof(wtmp));
-                       close(wf);
+       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;
+               case 'n':               /* don't set network */
+                       nflag = 1;
+                       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 (rc == 0)
-               time(&tv.tv_sec);
-       if (uflag) {
-               ap = asctime(gmtime(&tv.tv_sec));
-               tzn = "GMT";
-       } else {
-               struct tm *tp;
-               tp = localtime(&tv.tv_sec);
-               ap = asctime(tp);
-               tzn = timezone(tz.tz_minuteswest, tp->tm_isdst);
+
+       if (!rflag && time(&tval) == -1) {
+               perror("date: time");
+               exit(1);
+       }
+
+       format = "%a %b %e %H:%M:%S %Z %Y\n";
+
+       /* allow the operands in any order */
+       if (*argv && **argv == '+') {
+               format = *argv + 1;
+               ++argv;
        }
        }
-       printf("%.20s", ap);
-       if (tzn)
-               printf("%s", tzn);
-       printf("%s", ap+19);
-       exit(rc);
+
+       if (*argv) {
+               setthetime(*argv);
+               ++argv;
+       }
+
+       if (*argv && **argv == '+')
+               format = *argv + 1;
+
+       (void)strftime(buf, sizeof(buf), format, localtime(&tval));
+       (void)printf("%s", buf);
+       exit(retval);
 }
 
 }
 
-gtime()
+#define        ATOI2(ar)       ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+setthetime(p)
+       register char *p;
 {
 {
-       register int i, year, month;
-       int day, hour, mins, secs;
-       struct tm *L;
-       char x;
-
-       ep = ap;
-       while(*ep) ep++;
-       sp = ap;
-       while(sp < ep) {
-               x = *sp;
-               *sp++ = *--ep;
-               *ep = x;
-       }
-       sp = ap;
-       gettimeofday(&tv, 0);
-       L = localtime(&tv.tv_sec);
-       secs = gp(-1);
-       if (*sp != '.') {
-               mins = secs;
-               secs = 0;
-       } else {
-               sp++;
-               mins = gp(-1);
+       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();
        }
        }
-       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++;
+
+       /* 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", "");
        }
        }
-       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)
+badformat()
+{
+       (void)fprintf(stderr, "date: illegal time format.\n");
+       usage();
+}
+
+usage()
 {
 {
-       register int c, d;
-
-       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)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);
 }
 }