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
This commit is contained in:
parent
1b693d7494
commit
587714504f
@ -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.
|
||||
|
@ -45,6 +45,7 @@ static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
|
||||
#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.c 8.1 (Berkeley) 6/6/93";
|
||||
|
||||
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 timeval *tvp)
|
||||
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 *tvp)
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user