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>