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>
