Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Feb 1999 11:03:13 +1100 (EST)
From:      Gregory Bond <gnb@itga.com.au>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   bin/9868: patch for "date -a"
Message-ID:  <199902020003.LAA01915@hellcat.itga.com.au>

next in thread | raw e-mail | index | archive | help

>Number:         9868
>Category:       bin
>Synopsis:       Patch to add "date -a"
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb  1 16:10:01 PST 1999
>Closed-Date:
>Last-Modified:
>Originator:     Gregory Bond
>Release:        FreeBSD 3.0-STABLE i386
>Organization:
ITG Australia Ltd
>Environment:
FreeBSD hellcat.itga.com.au 3.0-STABLE FreeBSD 3.0-STABLE #7: Tue Feb  2 09:08:02 EST 1999     toor@hellcat.itga.com.au:/usr/src/sys/compile/Hellcat  i386


>Description:

	The following patches add "date -a" for people without access to
	ntp or whatever.  I sent them to phk a few weeks ago but I now realise
	this is a better way to submit it.

	My comments to phk at the time:
	
	>Attached are two diffs to add "date -a".
	>
	>The first is a diff to bin/date.[c1], pretty straight forward.
	>
	>The second is a diff to sys/kern/kern_time.c to add a third level of 
	>slew speed (100x for slews of >60 sec) which might be a bit more 
	>controversial. 
	>
	>A couple of unresolved issues:
	> - Do we make a wtmp record for slews.  If so, what format?
	> - I'm assuming negative timvals have negate tv_sec and negative 
	>   tv_usec, but that seems to depend on the C compiler's semantics 
	>   for "-ve % +ve" which isn't actually specified anywhere....
	>
	>This is the first time I've attempted to contribute anything to 
	>FreeBSD, so I'd be happy to receive feedback on anything here - 
	>coding standard, presentation of diffs, wording on man pages, 
	>whaterver you think is appropriate!
	>
	>As an aside: is there an xemacs c-style for FreeBSD coding standards?


>How-To-Repeat:
$ date -a -2.0
date: illegal option -- a
usage: date [-nu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHM]] ... 
            [-f fmt date | [[[[yy]mm]dd]HH]MM[.ss]] [+format]
$ 


>Fix:
	

diff -ru /usr/src/bin/date/date.1 ./date/date.1
--- /usr/src/bin/date/date.1	Wed May 13 17:56:44 1998
+++ ./date/date.1	Fri Dec 18 13:42:58 1998
@@ -49,17 +49,41 @@
 .Op Fl t Ar minutes_west
 .Op Fl v Ns Ar [+|-]val Ns Op ymwdHM
 .Ar ...
-.Op Fl f Ar fmt Ar date | [[[[yy]mm]dd]HH]MM[\&.ss]
+[ 
+.Fl f Ar fmt date | [[[[yy]mm]dd]HH]MM[\&.ss] |
+.Fl a Ar [+|-]ssss.fff 
+]
 .Op Cm + Ns Ar format
 .Sh DESCRIPTION
 .Nm Date
 displays the current date and time when invoked without arguments.
 Providing arguments will format the date and time in a user-defined
 way or set the date.
-Only the superuser may set the date.
+Only the superuser may set or adjust the date.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
+.It Fl a
+Adjust (slew) the system time by using the
+.Xr adjtime 2
+system call.  The argument is an offset in seconds and fractions of a
+second.  It can be positive (the system clock will run slightly fast
+until the specified adjustment is made) or negative (the system
+clock will run slightly slow until the specified adjustment is made).
+The amount of speedup or slowdown is typically one second every three
+minutes.  Note that 
+.Nm date -a
+will interact in unfortunate ways with programs such as 
+.Xr timed 8
+or 
+.Xr xntpd 8
+and should probably not be used of one if these programs is running.
+.Xr Adjtime 2
+will ensure that the time is monotonically increasing, which avoids
+problems with 
+.Xr cron
+and other time-based programs being confused if the system time steps
+forward or backwards.
 .It Fl d
 Set the kernel's value for daylight savings time.
 If
@@ -242,6 +266,15 @@
 sets the time to
 .Li "2:32 PM" ,
 without modifying the date.
+.Pp
+The command:
+.Bd -literal -offset indent
+date  -a -3.4
+.Ed
+.Pp
+will slow the system clock until 3.4 seconds have been taken off the
+system clock relative to real time.
+This should take about 10 minutes to complete.
 .Sh ENVIRONMENT
 The execution of
 .Nm
@@ -266,11 +299,13 @@
 a record of the user setting the time
 .El
 .Sh SEE ALSO
+.Xr adjtime 2 ,
 .Xr gettimeofday 2 ,
 .Xr strftime 3 ,
 .Xr strptime 3 ,
 .Xr utmp 5 ,
-.Xr timed 8
+.Xr timed 8 ,
+.Xr xntpd 8
 .Rs
 .%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
 .%A R. Gusella
@@ -296,6 +331,22 @@
 and
 .Xr timed
 fails.
+.Pp 
+When used with the
+.Ar -a
+flag,
+.Nm
+may print:
+.Ql Previous adjustment didn't complete: [-]sss.fff
+showing the amount uncompleted from the previous adjustment.  This may 
+indicate conflict between
+.Nm date -a
+and some other time-setting program such as
+.Xr named 8
+or
+.Xr xntp 8
+.
+
 .Sh BUGS
 The system attempts to keep the date in a format closely compatible
 with
diff -ru /usr/src/bin/date/date.c ./date/date.c
--- /usr/src/bin/date/date.c	Sun Oct  4 02:29:59 1998
+++ ./date/date.c	Fri Dec 18 12:19:11 1998
@@ -63,9 +63,12 @@
 time_t tval;
 int retval, nflag;
 
+static void adjustthetime __P((const char *));
 static void setthetime __P((const char *, const char *));
+static void badadjust __P((void));
 static void badformat __P((void));
 static void usage __P((void));
+static const char *fmttimeval __P((const struct timeval *));
 
 int logwtmp __P((char *, char *, char *));
 
@@ -84,6 +87,7 @@
 	struct vary *v;
 	const struct vary *badv;
 	struct tm lt;
+	const char *adjstring = 0;
 
 	v = NULL;
 	fmt = NULL;
@@ -91,8 +95,11 @@
 	tz.tz_dsttime = tz.tz_minuteswest = 0;
 	rflag = 0;
 	set_timezone = 0;
-	while ((ch = getopt(argc, argv, "d:f:nr:t:uv:")) != -1)
+	while ((ch = getopt(argc, argv, "a:d:f:nr:t:uv:")) != -1)
 		switch((char)ch) {
+		case 'a':
+			adjstring = optarg;
+			break;
 		case 'd':		/* daylight savings time */
 			tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
 			if (endptr == optarg || *endptr != '\0')
@@ -135,6 +142,14 @@
 	if (set_timezone && settimeofday((struct timeval *)NULL, &tz))
 		err(1, "settimeofday (timezone)");
 
+	/* -a is not compatible with any other args */
+	if (adjstring != NULL) {
+		if (*argv)
+			usage();
+		adjustthetime(adjstring);
+		exit(retval);
+	}
+	
 	if (!rflag && time(&tval) == -1)
 		err(1, "time");
 
@@ -267,6 +282,82 @@
 }
 
 static void
+adjustthetime(adj)
+	const char *adj;
+{
+	struct	timeval newdelta;
+	struct	timeval olddelta;
+	long	sec = 0;
+	long	usec = 0;
+	const char *a = adj;
+	char	*e;
+	
+	sec = strtol(a, &e, 10);
+	if (e == a) 
+		badadjust();
+	if (*e) {
+		if (*e == '.') {
+			a = e+1;
+			usec = strtol(a, &e, 10);
+			if (a == e || *e) {
+				badadjust();
+			}
+		} else {
+			badadjust();
+		}
+	}
+		
+	newdelta.tv_sec = sec;
+	if (sec < 0) {
+		newdelta.tv_usec = -usec;
+	} else {
+		newdelta.tv_usec = usec;
+	}
+	if (adjtime(&newdelta,&olddelta) < 0)
+		err(1, "adjtime");
+	/* XXX ?? logwtmp("{", "dateslew", ""); */
+	if ((a = getlogin()) == NULL)
+		a = "???";
+	syslog(LOG_AUTH | LOG_NOTICE, "date slewed %s by %s",
+	       fmttimeval(&newdelta), a);
+	if (olddelta.tv_sec != 0 || olddelta.tv_usec != 0) {
+		warnx("Previous adjustment didn't complete: %s",
+		      fmttimeval(&olddelta));
+	}
+}
+
+/*
+ * Format a timeval into a static string.  Need to be careful of
+ * negative values in the usec and cut trailing zeros from usecs field
+ */
+static const char *
+fmttimeval(const struct timeval *tp)
+{
+	static char buf[20];
+	char	*ep;
+	int	n;
+	long	usec = tp->tv_usec;
+	
+	if (usec < 0) 
+		usec = -usec;
+	
+	n = snprintf(buf, sizeof(buf), "%ld.%06ld", tp->tv_sec, usec);
+	if (n > sizeof(buf))
+	    n = sizeof(buf);
+	ep = buf + n - 1;
+	while (ep > buf + 1 && *ep == '0' && ep[-1] != '.')
+		*ep-- = 0;
+	return buf;
+}
+
+static void
+badadjust()
+{
+	warnx("illegal adjustment format");
+	usage();
+}
+
+static void
 badformat()
 {
 	warnx("illegal time format");
@@ -279,6 +370,6 @@
 	(void)fprintf(stderr, "%s\n%s\n",
 	    "usage: date [-nu] [-d dst] [-r seconds] [-t west] "
 	    "[-v[+|-]val[ymwdHM]] ... ",
-	    "            [-f fmt date | [[[[yy]mm]dd]HH]MM[.ss]] [+format]");
+	    "            [-f fmt date | [[[[yy]mm]dd]HH]MM[.ss] | -a [+|-]sss.fff] [+format]");
 	exit(1);
 }




diff -ru /usr/src/sys/kern/kern_time.c kern/kern_time.c
--- /usr/src/sys/kern/kern_time.c	Wed Dec  2 11:44:37 1998
+++ kern/kern_time.c	Fri Dec 18 13:49:56 1998
@@ -324,6 +324,7 @@
 int	tickdelta;			/* current clock skew, us. per tick */
 long	timedelta;			/* unapplied time correction, us. */
 static long	bigadj = 1000000;	/* use 10x skew above bigadj us. */
+static long	hugeadj = 10000000;	/* use 100x skew above hugeadj us. */
 
 #ifndef _SYS_SYSPROTO_H_
 struct adjtime_args {
@@ -355,7 +356,9 @@
 	 * overshoot and start taking us away from the desired final time.
 	 */
 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
-	if (ndelta > bigadj || ndelta < -bigadj)
+	if (ndelta > hugeadj || ndelta < -hugeadj)
+		ntickdelta = 100 * tickadj;
+	else if (ndelta > bigadj || ndelta < -bigadj)
 		ntickdelta = 10 * tickadj;
 	else
 		ntickdelta = tickadj;
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199902020003.LAA01915>