>From add5f660b7bd0cdb93ee36a941f151c615d4d5c3 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Tue, 28 Jul 2015 18:13:56 -0700
Subject: [PROPOSED PATCH 2/2] Port 'date' better to POSIX 1003.1-2001 and
 later

* Makefile: Remove no-longer-needed comments.
* NEWS, date.1: Document this.
* date.c [HAVE_ADJTIME || HAVE_SETTIMEOFDAY]:
Don't include sys/time.h.
(main): Remove support for -a, -d, -t.
(reset): Use clock_settime, not the nonstandard stime.
(nondigit): Remove; no longer needed.
* private.h (HAVE_ADJTIME, HAVE_SETTIMEOFDAY): Remove.
---
 Makefile  |   5 ---
 NEWS      |   8 ++++
 date.1    |  34 ----------------
 date.c    | 130 +++++++++-----------------------------------------------------
 private.h |  10 +----
 5 files changed, 27 insertions(+), 160 deletions(-)

diff --git a/Makefile b/Makefile
index 8702119..09136f9 100644
--- a/Makefile
+++ b/Makefile
@@ -102,7 +102,6 @@ LDLIBS=
 
 # Add the following to the end of the "CFLAGS=" line as needed.
 #  -DBIG_BANG=-9999999LL if the Big Bang occurred at time -9999999 (see zic.c)
-#  -DHAVE_ADJTIME=0 if 'adjtime' does not exist (SVR0?)
 #  -DHAVE_DOS_FILE_NAMES if file names have drive specifiers etc. (MS-DOS)
 #  -DHAVE_GETTEXT=1 if 'gettext' works (GNU, Linux, Solaris); also see LDLIBS
 #  -DHAVE_INCOMPATIBLE_CTIME_R=1 if your system's time.h declares
@@ -113,10 +112,6 @@ LDLIBS=
 #  -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
 #	This defaults to 1 if a working localtime_rz seems to be available.
 #	localtime_rz can make zdump significantly faster, but is nonstandard.
-#  -DHAVE_SETTIMEOFDAY=0 if settimeofday does not exist (SVR0?)
-#  -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
-#  -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD)
-#  -DHAVE_SETTIMEOFDAY=3 if settimeofday ignores 2nd arg (4.4BSD)
 #  -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h"
 #  -DHAVE_STRFTIME_L=1 if <time.h> declares locale_t and strftime_l
 #	This defaults to 0 if _POSIX_VERSION < 200809, 1 otherwise.
diff --git a/NEWS b/NEWS
index 45065e4..e6ece37 100644
--- a/NEWS
+++ b/NEWS
@@ -48,6 +48,14 @@ Unreleased, experimental changes
     Some Visual Studio 2013 warnings have been suppressed.
     (Thanks to Kees Dekker.)
 
+    date now sets the time of day via the POSIX clock_settime function
+    instead of via the older nonstandard settimeofday function.
+    date's -a, -d, and -t options have been removed.  Long obsolescent,
+    they were usable only by the superuser, and their implementation
+    had porting problems.  Builders no longer need to configure
+    HAVE_ADJTIME and HAVE_SETTIMEOFDAY.  (Thanks to Kees Dekker for
+    pointing out the problem.)
+
     The implementation of date's -n option, which has long been a
     no-op in practice, has been greatly simplified and the -n option
     is no longer documented.  (Thanks to Kees Dekker for pointing out
diff --git a/date.1 b/date.1
index 567c636..7fd4848 100644
--- a/date.1
+++ b/date.1
@@ -15,14 +15,6 @@ date \- show and set date and time
 .B \*-r
 .I seconds
 ] [
-.B \*-d
-.I dsttype
-] [
-.B \*-t
-.I minutes-west
-] [
-\fB\*-a \fR[\fB+\fR|\fB\*-]\fIsss\fB.\fIfff\fR
-] [
 .BI + format
 ] [
 \fR[\fIyyyy\fR]\fImmddhhmm\fR[\fIyy\fR][\fB.\fIss\fR]
@@ -151,32 +143,6 @@ past the epoch of 1970-01-01 00:00:00 UTC, where
 .I seconds
 should be an integer, either decimal, octal (leading 0), or
 hexadecimal (leading 0x), preceded by an optional sign.
-.TP
-.BI "\*-d " dsttype
-Set the kernel-stored Daylight Saving Time type to the given value.
-(The kernel-stored DST type is used mostly by
-.q "old"
-binaries.)
-.TP
-.BI "\*-t " minutes-west
-Set the kernel-stored
-.q "minutes west of UTC"
-value to the one given on the
-command line.
-(The kernel-stored DST type is used mostly by
-.q "old"
-binaries.)
-.TP
-.BI "\*-a " adjustment
-Change the time forward (or backward) by the number of seconds
-(and fractions thereof) specified in the
-.I adjustment
-argument.
-Either the seconds part or the fractions part of the argument (but not both)
-may be omitted.
-On BSD-based systems,
-the adjustment is made by changing the rate at which time advances;
-on System-V-based systems, the adjustment is made by changing the time.
 .SH FILES
 .ta \w'/usr/local/etc/zoneinfo/posixrules\0\0'u
 /usr/lib/locale/\f2L\fP/LC_TIME	description of time locale \f2L\fP
diff --git a/date.c b/date.c
index 2a55505..a273f81 100644
--- a/date.c
+++ b/date.c
@@ -16,9 +16,6 @@
  */
 
 #include "private.h"
-#if HAVE_ADJTIME || HAVE_SETTIMEOFDAY
-#include "sys/time.h"	/* for struct timeval, struct timezone */
-#endif /* HAVE_ADJTIME || HAVE_SETTIMEOFDAY */
 #include "locale.h"
 #if HAVE_UTMPX_H
 #include "utmpx.h"
@@ -59,7 +56,6 @@ static void		display(const char *, time_t);
 static void		dogmt(void);
 static void		errensure(void);
 static void		iffy(time_t, time_t, const char *, const char *);
-static const char *	nondigit(const char *);
 static void		oops(const char *);
 static void		reset(time_t);
 static void		timeout(FILE *, const char *, const struct tm *);
@@ -75,13 +71,7 @@ main(const int argc, char *argv[])
 	register const char *	cp;
 	register int		ch;
 	register bool		dousg;
-	register bool		aflag = false;
-	register bool		dflag = false;
-	register bool		tflag = false;
 	register bool		rflag = false;
-	register int		minuteswest;
-	register int		dsttime;
-	register double		adjust;
 	time_t			now;
 	time_t			t;
 	intmax_t		secs;
@@ -99,7 +89,7 @@ main(const int argc, char *argv[])
 #endif /* HAVE_GETTEXT */
 	t = now = time(NULL);
 	format = value = NULL;
-	while ((ch = getopt(argc, argv, "ucr:nd:t:a:")) != EOF && ch != -1) {
+	while ((ch = getopt(argc, argv, "ucr:n")) != EOF && ch != -1) {
 		switch (ch) {
 		default:
 			usage();
@@ -129,55 +119,6 @@ main(const int argc, char *argv[])
 			break;
 		case 'n':		/* don't set network (ignored) */
 			break;
-		case 'd':		/* daylight saving time */
-			if (dflag) {
-				fprintf(stderr,
-					_("date: error: multiple -d's used"));
-				usage();
-			}
-			dflag = true;
-			cp = optarg;
-			dsttime = atoi(cp);
-			if (*cp == '\0' || *nondigit(cp) != '\0')
-				wildinput(_("-t value"), optarg,
-					_("must be a non-negative number"));
-			break;
-		case 't':		/* minutes west of UTC */
-			if (tflag) {
-				fprintf(stderr,
-					_("date: error: multiple -t's used"));
-				usage();
-			}
-			tflag = true;
-			cp = optarg;
-			minuteswest = atoi(cp);
-			if (*cp == '+' || *cp == '-')
-				++cp;
-			if (*cp == '\0' || *nondigit(cp) != '\0')
-				wildinput(_("-d value"), optarg,
-					_("must be a number"));
-			break;
-		case 'a':		/* adjustment */
-			if (aflag) {
-				fprintf(stderr,
-					_("date: error: multiple -a's used"));
-				usage();
-			}
-			aflag = true;
-			cp = optarg;
-			adjust = atof(cp);
-			if (*cp == '+' || *cp == '-')
-				++cp;
-			if (*cp == '\0' || strcmp(cp, ".") == 0)
-				wildinput(_("-a value"), optarg,
-					_("must be a number"));
-			cp = nondigit(cp);
-			if (*cp == '.')
-				++cp;
-			if (*nondigit(cp) != '\0')
-				wildinput(_("-a value"), optarg,
-					_("must be a number"));
-			break;
 		}
 	}
 	while (optind < argc) {
@@ -240,44 +181,6 @@ _("date: error: multiple values in command line\n"));
 	/*
 	** Entire command line has now been checked.
 	*/
-	if (aflag) {
-#if HAVE_ADJTIME
-		struct timeval	tv;
-
-		tv.tv_sec = (int) adjust;
-		tv.tv_usec = (int) ((adjust - tv.tv_sec) * 1000000L);
-		if (adjtime(&tv, NULL) != 0)
-			oops("adjtime");
-#endif /* HAVE_ADJTIME */
-#if !HAVE_ADJTIME
-		reset(now + adjust);
-#endif /* !HAVE_ADJTIME */
-		/*
-		** Sun silently ignores everything else; we follow suit.
-		*/
-		exit(retval);
-	}
-	if (dflag || tflag) {
-#if HAVE_SETTIMEOFDAY == 2
-		struct timezone	tz;
-
-		if (!dflag || !tflag)
-			if (gettimeofday(NULL, &tz) != 0)
-				oops("gettimeofday");
-		if (dflag)
-			tz.tz_dsttime = dsttime;
-		if (tflag)
-			tz.tz_minuteswest = minuteswest;
-		if (settimeofday(NULL, &tz) != 0)
-			oops("settimeofday");
-#endif /* HAVE_SETTIMEOFDAY == 2 */
-#if HAVE_SETTIMEOFDAY != 2
-		(void) dsttime;
-		(void) minuteswest;
-		fprintf(stderr,
-_("date: warning: kernel doesn't keep -d/-t information, option ignored\n"));
-#endif /* HAVE_SETTIMEOFDAY != 2 */
-	}
 
 	if (value) {
 		reset(t);
@@ -320,7 +223,8 @@ dogmt(void)
 
 /*
 ** We assume we're on a POSIX-based system,
-** should use stime, and should write utmp entries if HAVE_UTMPX_H,
+** should use clock_settime if CLOCK_REALTIME is defined,
+** and should write utmp entries if HAVE_UTMPX_H,
 ** and don't have network notification to worry about.
 */
 
@@ -342,10 +246,21 @@ reset(time_t newt)
 #endif
 
 	/*
-	** Wouldn't it be great if stime returned the old time?
+	** Wouldn't it be great if clock_settime returned the old time?
 	*/
-	if (stime(&newt) != 0)
-		oops("stime");
+	int clock_settime_result;
+#ifdef CLOCK_REALTIME
+	struct timespec ts;
+	ts.tv_sec = newt;
+	ts.tv_nsec = 0;
+	clock_settime_result = clock_settime(CLOCK_REALTIME, &ts);
+#else
+	clock_settime_result = -1;
+	errno = EPERM;
+#endif
+	if (clock_settime_result != 0)
+	  oops("clock_settime");
+
 #if HAVE_UTMPX_H
 	sx.before.ut_type = OLD_TIME;
 	sx.before.ut_tv.tv_sec = oldt;
@@ -388,20 +303,11 @@ errensure(void)
 		retval = EXIT_FAILURE;
 }
 
-static const char * ATTRIBUTE_PURE
-nondigit(register const char *cp)
-{
-	while (is_digit(*cp))
-		++cp;
-	return cp;
-}
-
 static void
 usage(void)
 {
 	fprintf(stderr,
 		       _("date: usage: date [-u] [-c] [-r seconds]"
-			 " [-d dst] [-t min-west] [-a sss.fff]"
 			 " [[yyyy]mmddhhmm[yyyy][.ss]] [+format]\n"));
 	errensure();
 	exit(retval);
@@ -644,7 +550,7 @@ checkfinal(char const *value, bool didusg, time_t t, time_t oldnow)
 ** So we perform this final check, deferring it until after the time has
 ** been set; it may take a while, and we don't want to introduce an unnecessary
 ** lag between the time the user enters their command and the time that
-** stime/settimeofday is called.
+** clock_settime is called.
 **
 ** We just check nearby times to see if any have the same representation
 ** as the time that convert returned.  We work our way out from the center
diff --git a/private.h b/private.h
index 71a02d8..184da8f 100644
--- a/private.h
+++ b/private.h
@@ -19,13 +19,9 @@
 
 /*
 ** Defaults for preprocessor symbols.
-** You can override these in your C compiler options, e.g. '-DHAVE_ADJTIME=0'.
+** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
 */
 
-#ifndef HAVE_ADJTIME
-#define HAVE_ADJTIME		1
-#endif /* !defined HAVE_ADJTIME */
-
 #ifndef HAVE_GETTEXT
 #define HAVE_GETTEXT		0
 #endif /* !defined HAVE_GETTEXT */
@@ -38,10 +34,6 @@
 #define HAVE_LINK		1
 #endif /* !defined HAVE_LINK */
 
-#ifndef HAVE_SETTIMEOFDAY
-#define HAVE_SETTIMEOFDAY	3
-#endif /* !defined HAVE_SETTIMEOFDAY */
-
 #ifndef HAVE_STRDUP
 #define HAVE_STRDUP 1
 #endif
-- 
2.1.4

