Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 Jun 2012 14:26:52 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r236852 - head/usr.bin/touch
Message-ID:  <201206101426.q5AEQqE7002347@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Sun Jun 10 14:26:51 2012
New Revision: 236852
URL: http://svn.freebsd.org/changeset/base/236852

Log:
  touch: Add the -d option from POSIX.1-2008.
  
  This is much like -t but with a different format which is ISO8601-like and
  allows fractions of a second.
  
  The precision is limited to microseconds because of utimes() and friends,
  even though stat() returns nanoseconds.
  
  MFC after:	10 days

Modified:
  head/usr.bin/touch/touch.1
  head/usr.bin/touch/touch.c

Modified: head/usr.bin/touch/touch.1
==============================================================================
--- head/usr.bin/touch/touch.1	Sun Jun 10 13:28:14 2012	(r236851)
+++ head/usr.bin/touch/touch.1	Sun Jun 10 14:26:51 2012	(r236852)
@@ -31,7 +31,7 @@
 .\"     @(#)touch.1	8.3 (Berkeley) 4/28/95
 .\" $FreeBSD$
 .\"
-.Dd February 4, 2012
+.Dd June 10, 2012
 .Dt TOUCH 1
 .Os
 .Sh NAME
@@ -43,6 +43,7 @@
 .Op Fl achm
 .Op Fl r Ar file
 .Op Fl t Ar [[CC]YY]MMDDhhmm[.SS]
+.Op Fl d Ar YYYY-MM-DDThh:mm:SS[.frac][tz]
 .Ar
 .Sh DESCRIPTION
 The
@@ -61,8 +62,10 @@ individually.
 Selecting both is equivalent to the default.
 By default, the timestamps are set to the current time.
 The
+.Fl d
+and
 .Fl t
-flag explicitly specifies a different time, and the
+flags explicitly specify a different time, and the
 .Fl r
 flag specifies to set the times those of the specified file.
 The
@@ -109,6 +112,41 @@ The
 .Nm
 utility does not treat this as an error.
 No error messages are displayed and the exit value is not affected.
+.It Fl d
+Change the access and modification times to the specified time instead
+of the current time of day.
+The argument is of the form
+.Dq YYYY-MM-DDThh:mm:SS[.frac][tz]
+where the letters represent the following:
+.Bl -tag -width Ds -compact -offset indent
+.It Ar YYYY
+The year.
+.It Ar MM
+The month of the year, from 01 to 12.
+.It Ar DD
+The day of the month, from 01 to 31.
+.It Ar T
+The letter
+.Li T
+or a space.
+.It Ar hh
+The hour of the day, from 00 to 23.
+.It Ar mm
+The minute of the hour, from 00 to 59.
+.It Ar SS
+The second of the minute, from 00 to 61.
+.It Ar .frac
+An optional fraction,
+consisting of a period or a comma followed by one or more digits.
+The number of significant digits depends on the kernel configuration and
+the filesystem, and may be zero.
+.It Ar tz
+An optional letter
+.Li Z
+indicating the time is in
+.Tn UTC .
+Otherwise, the time is assumed to be in local time.
+.El
 .It Fl h
 If the file is a symbolic link, change the times of the link
 itself rather than the file that the link points to.

Modified: head/usr.bin/touch/touch.c
==============================================================================
--- head/usr.bin/touch/touch.c	Sun Jun 10 13:28:14 2012	(r236851)
+++ head/usr.bin/touch/touch.c	Sun Jun 10 14:26:51 2012	(r236852)
@@ -45,6 +45,7 @@ static const char sccsid[] = "@(#)touch.
 #include <sys/stat.h>
 #include <sys/time.h>
 
+#include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -57,6 +58,7 @@ static const char sccsid[] = "@(#)touch.
 
 void	stime_arg1(char *, struct timeval *);
 void	stime_arg2(char *, int, struct timeval *);
+void	stime_darg(char *, struct timeval *);
 void	stime_file(char *, struct timeval *);
 int	timeoffset(char *);
 void	usage(char *);
@@ -79,7 +81,7 @@ main(int argc, char *argv[])
 	if (gettimeofday(&tv[0], NULL))
 		err(1, "gettimeofday");
 
-	while ((ch = getopt(argc, argv, "A:acfhmr:t:")) != -1)
+	while ((ch = getopt(argc, argv, "A:acd:fhmr:t:")) != -1)
 		switch(ch) {
 		case 'A':
 			Aflag = timeoffset(optarg);
@@ -90,6 +92,10 @@ main(int argc, char *argv[])
 		case 'c':
 			cflag = 1;
 			break;
+		case 'd':
+			timeset = 1;
+			stime_darg(optarg, tv);
+			break;
 		case 'f':
 			/* No-op for compatibility. */
 			break;
@@ -320,6 +326,50 @@ stime_arg2(char *arg, int year, struct t
 	tvp[0].tv_usec = tvp[1].tv_usec = 0;
 }
 
+void
+stime_darg(char *arg, struct timeval *tvp)
+{
+	struct tm t = { .tm_sec = 0 };
+	const char *fmt, *colon;
+	char *p;
+	int val, isutc = 0;
+
+	tvp[0].tv_usec = 0;
+	t.tm_isdst = -1;
+	colon = strchr(arg, ':');
+	if (colon == NULL || strchr(colon + 1, ':') == NULL)
+		goto bad;
+	fmt = strchr(arg, 'T') != NULL ? "%Y-%m-%dT%H:%M:%S" :
+	    "%Y-%m-%d %H:%M:%S";
+	p = strptime(arg, fmt, &t);
+	if (p == NULL)
+		goto bad;
+	/* POSIX: must have at least one digit after dot */
+	if ((*p == '.' || *p == ',') && isdigit((unsigned char)p[1])) {
+		p++;
+		val = 100000;
+		while (isdigit((unsigned char)*p)) {
+			tvp[0].tv_usec += val * (*p - '0');
+			p++;
+			val /= 10;
+		}
+	}
+	if (*p == 'Z') {
+		isutc = 1;
+		p++;
+	}
+	if (*p != '\0')
+		goto bad;
+
+	tvp[0].tv_sec = isutc ? timegm(&t) : mktime(&t);
+
+	tvp[1] = tvp[0];
+	return;
+
+bad:
+	errx(1, "out of range or illegal time specification: YYYY-MM-DDThh:mm:SS[.frac][tz]");
+}
+
 /* Calculate a time offset in seconds, given an arg of the format [-]HHMMSS. */
 int
 timeoffset(char *arg)
@@ -364,7 +414,9 @@ stime_file(char *fname, struct timeval *
 void
 usage(char *myname)
 {
-	fprintf(stderr, "usage:\n" "%s [-A [-][[hh]mm]SS] [-achm] [-r file] "
-		"[-t [[CC]YY]MMDDhhmm[.SS]] file ...\n", myname);
+	fprintf(stderr, "usage: %s [-A [-][[hh]mm]SS] [-achm] [-r file] "
+		"[-t [[CC]YY]MMDDhhmm[.SS]]\n"
+		"       [-d YYYY-MM-DDThh:mm:SS[.frac][tz]] "
+		"file ...\n", myname);
 	exit(1);
 }



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