summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Fiddaman <omnios@citrus-it.co.uk>2020-09-05 22:23:36 +0000
committerAndy Fiddaman <omnios@citrus-it.co.uk>2020-09-17 18:19:33 +0000
commitb7a7784945b3504d0b69ea02a08e1cddb5578907 (patch)
tree68d892b0bea31b71ddf9a217932de4462f852236
parent260b78324e5b8479cc94f897a36e996f026c3fef (diff)
downloadillumos-joyent-b7a7784945b3504d0b69ea02a08e1cddb5578907.tar.gz
13111 Want futimes(), lutimes() and timespec/timeval conversion macros
Reviewed by: Robert Mustacchi <rm@fingolfin.org> Reviewed by: Marco van Wieringen <mvw@planets.elm.net> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/lib/libc/port/mapfile-vers6
-rw-r--r--usr/src/lib/libc/port/sys/utimesys.c28
-rw-r--r--usr/src/man/man2/Makefile5
-rw-r--r--usr/src/man/man2/utimes.258
-rw-r--r--usr/src/man/man3head/Makefile9
-rw-r--r--usr/src/man/man3head/timespec.3head106
-rw-r--r--usr/src/man/man3lib/libc.3lib251
-rw-r--r--usr/src/pkg/manifests/system-header.mf7
-rw-r--r--usr/src/pkg/manifests/system-kernel.man2.inc5
-rw-r--r--usr/src/pkg/manifests/system-test-libctest.mf3
-rw-r--r--usr/src/prototypes/prototype.man3x2
-rw-r--r--usr/src/test/libc-tests/cfg/symbols/sys_time_h.cfg14
-rw-r--r--usr/src/test/libc-tests/runfiles/default.run3
-rw-r--r--usr/src/test/libc-tests/tests/Makefile4
-rw-r--r--usr/src/test/libc-tests/tests/utimes.c521
-rw-r--r--usr/src/uts/common/sys/time.h27
16 files changed, 893 insertions, 156 deletions
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 6a4c274258..be5b7e73bf 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -78,6 +78,12 @@ $if _x86 && _ELF64
$add amd64
$endif
+SYMBOL_VERSION ILLUMOS_0.34 {
+ protected:
+ futimes;
+ lutimes;
+} ILLUMOS_0.33;
+
SYMBOL_VERSION ILLUMOS_0.33 {
protected:
c16rtomb;
diff --git a/usr/src/lib/libc/port/sys/utimesys.c b/usr/src/lib/libc/port/sys/utimesys.c
index dc917f27ae..55e53dbb53 100644
--- a/usr/src/lib/libc/port/sys/utimesys.c
+++ b/usr/src/lib/libc/port/sys/utimesys.c
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
+
#include "lint.h"
#include <string.h>
#include <utime.h>
@@ -67,8 +71,8 @@ utime(const char *path, const struct utimbuf *times)
return (utimensat(AT_FDCWD, path, tsp, 0));
}
-int
-utimes(const char *path, const struct timeval times[2])
+static int
+utimes_impl(const char *path, const struct timeval times[2], int flag)
{
struct timeval ltimes[2];
timespec_t ts[2];
@@ -86,7 +90,19 @@ utimes(const char *path, const struct timeval times[2])
ts[1].tv_nsec = ltimes[1].tv_usec * 1000;
tsp = ts;
}
- return (utimensat(AT_FDCWD, path, tsp, 0));
+ return (utimensat(AT_FDCWD, path, tsp, flag));
+}
+
+int
+utimes(const char *path, const struct timeval times[2])
+{
+ return (utimes_impl(path, times, 0));
+}
+
+int
+lutimes(const char *path, const struct timeval times[2])
+{
+ return (utimes_impl(path, times, AT_SYMLINK_NOFOLLOW));
}
#pragma weak _futimesat = futimesat
@@ -115,3 +131,9 @@ futimesat(int fd, const char *path, const struct timeval times[2])
return (utimensat(fd, path, tsp, 0));
}
+
+int
+futimes(int fd, const struct timeval times[2])
+{
+ return (futimesat(fd, NULL, times));
+}
diff --git a/usr/src/man/man2/Makefile b/usr/src/man/man2/Makefile
index 556de2d03b..8f664a56fc 100644
--- a/usr/src/man/man2/Makefile
+++ b/usr/src/man/man2/Makefile
@@ -15,6 +15,7 @@
# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 2018, Joyent, Inc. All rights reserved.
# Copyright 2017 Peter Tribble
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
include $(SRC)/Makefile.master
@@ -196,6 +197,7 @@ MANLINKS= _Exit.2 \
fstat.2 \
fstatat.2 \
fstatvfs.2 \
+ futimes.2 \
futimesat.2 \
futimens.2 \
getaudit_addr.2 \
@@ -213,6 +215,7 @@ MANLINKS= _Exit.2 \
lchown.2 \
linkat.2 \
lstat.2 \
+ lutimes.2 \
mkdirat.2 \
mknodat.2 \
openat.2 \
@@ -396,7 +399,9 @@ umount2.2 := LINKSRC = umount.2
unlinkat.2 := LINKSRC = unlink.2
futimens.2 := LINKSRC = utimes.2
+futimes.2 := LINKSRC = utimes.2
futimesat.2 := LINKSRC = utimes.2
+lutimes.2 := LINKSRC = utimes.2
utimensat.2 := LINKSRC = utimes.2
vforkx.2 := LINKSRC = vfork.2
diff --git a/usr/src/man/man2/utimes.2 b/usr/src/man/man2/utimes.2
index 69eee29879..404fea7180 100644
--- a/usr/src/man/man2/utimes.2
+++ b/usr/src/man/man2/utimes.2
@@ -43,12 +43,12 @@
.\" Portions Copyright (c) 1992, X/Open Company Limited. All Rights Reserved.
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2014, Joyent, Inc.
+.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
.\"
-.TH UTIMES 2 "Dec 20, 2014"
+.TH UTIMES 2 "Sep 06, 2020"
.SH NAME
-utimes, futimesat \- set file access and modification times
+utimes, lutimes, futimes, futimesat, utimens, utimensat \- set file access and modification times
.SH SYNOPSIS
-.LP
.nf
#include <sys/time.h>
@@ -57,6 +57,16 @@ utimes, futimesat \- set file access and modification times
.LP
.nf
+\fBint\fR \fBlutimes\fR(\fBconst char *\fR\fIpath\fR, \fBconst struct timeval\fR \fItimes\fR[2]);
+.fi
+
+.LP
+.nf
+\fBint\fR \fBfutimes\fR(\fBint\fR \fIfildes\fR, \fBconst struct timeval\fR \fItimes\fR[2]);
+.fi
+
+.LP
+.nf
\fBint\fR \fBfutimesat\fR(\fBint\fR \fIfildes\fR, \fBconst char *\fR\fIpath\fR,
\fBconst struct timeval\fR \fItimes\fR[2]);
.fi
@@ -65,18 +75,27 @@ utimes, futimesat \- set file access and modification times
.nf
#include <sys/stat.h>
-\fBint\fR \fBfutimens\fR(\fBint\fR \fIfiledes\fR, \fBconst timespec_t\fR \fInstimes[2]\fR);
+\fBint\fR \fBfutimens\fR(\fBint\fR \fIfildes\fR, \fBconst timespec_t\fR \fInstimes[2]\fR);
-\fBint\fR \fButimensat\fR(\fBint\fR \fIfiledes\fR, \fBconst char *\fR\fIpath\fR,
+\fBint\fR \fButimensat\fR(\fBint\fR \fIfildes\fR, \fBconst char *\fR\fIpath\fR,
\fBconst timespec_t\fR \fInstimes[2]\fR, \fBint\fR \fIflag\fR);
.SH DESCRIPTION
-.LP
The \fButimes()\fR function sets the access and modification times of the file
pointed to by the \fIpath\fR argument to the value of the \fItimes\fR argument.
It allows time specifications accurate to the microsecond.
.sp
.LP
+The \fBlutimes()\fR function operates like \fButimes()\fR except if \fIpath\fR
+points to a symbolic link; in that case \fBlutimes()\fR changes the access and
+modifications times of the link, while \fButimes()\fR changes the file that
+is referenced by the link.
+.sp
+.LP
+The \fBfutimes()\fR function sets the access and modification times of the
+file referenced by the file descriptor \fIfildes\fR.
+.sp
+.LP
The \fBfutimesat()\fR function also sets access and modification times. See
\fBfsattr\fR(5). If \fIpath\fR is a relative path name, however,
\fBfutimesat()\fR resolves the path relative to the \fIfildes\fR argument
@@ -84,7 +103,7 @@ rather than the current working directory. If \fIfildes\fR is set to
\fBAT_FDCWD\fR, defined in <\fBfcntl.h\fR>, \fBfutimesat()\fR resolves the path
relative to the current working directory. If \fIpath\fR is a null pointer,
\fBfutimesat()\fR sets the access and modification times on the file referenced
-by \fIfildes\fR. The \fIfildes\fR argument is ignored even when
+by \fIfildes\fR. The \fIfildes\fR argument is ignored if
\fBfutimesat()\fR is provided with an absolute path.
.sp
.LP
@@ -107,28 +126,28 @@ The \fBfutimens()\fR and \fButimensat()\fR functions also set access and
modification times; however, instead of taking \fBstruct timeval\fR, they take
\fBtimespec_t\fR which allows for nanosecond granularity. The \fBfutimens()\fR
function sets the access and modification times on the file descriptor
-referenced by \fIfiledes\fR.
+referenced by \fIfildes\fR.
.sp
.LP
The \fButimensat()\fR function determines the file to set the access and
-modification times in an similar way to \fBfutemsat()\fR. If the argument
-\fIpath\fR is an absolute path, then the argument \fIfiledes\fR is ignored;
+modification times in an similar way to \fBfutimesat()\fR. If the argument
+\fIpath\fR is an absolute path, then the argument \fIfildes\fR is ignored;
otherwise, \fIpath\fR is interpreted as a path relative to the directory
-specified by \fIfiledes\fR. If \fIfiledes\fR is set to \fBAT_FDCWD\fR, then
+specified by \fIfildes\fR. If \fIfildes\fR is set to \fBAT_FDCWD\fR, then
\fIpath\fR is resolved relative to the current working directory. The behavior
when encountering symbolic links may be controlled by the value of the
\fIflag\fR argument. If the value of flag is the constant
\fBAT_SYMLINK_NOFOLLOW\fR, then when a symbolic link is encountered while
resolving a path, it will not be followed. Otherwise, the value of \fIflag\fR
-should be \fB0\fR.
+should be \fB0\fR. Note that, unlike \fBfutimesat()\fR, \fButimensat()\fR
+does not accept a null pointer for the \fIpath\fR argument.
.SH RETURN VALUES
-.LP
Upon successful completion, \fB0\fR is returned. Otherwise, \fB\(mi1\fR is
returned, \fBerrno\fR is set to indicate the error, and the file times will not
be affected.
.SH ERRORS
-.LP
-The \fButimes()\fR, \fBfutimesat()\fR, \fBfutimens()\fR, and \fButimensat()\fR
+The \fButimes()\fR, \fBlutimes()\fR, \fBfutimes()\fR, \fBfutimesat()\fR,
+\fBfutimens()\fR, and \fButimensat()\fR
functions will fail if:
.sp
.ne 2
@@ -147,9 +166,7 @@ process does not match the owner of the file and write access is denied.
\fB\fBEFAULT\fR\fR
.ad
.RS 16n
-The \fIpath\fR or \fItimes\fR argument points to an illegal address. For
-\fBfutimesat()\fR, \fIpath\fR might have the value \fINULL\fR if the
-\fIfildes\fR argument refers to a valid open file descriptor.
+The \fIpath\fR or \fItimes\fR argument points to an illegal address.
.RE
.sp
@@ -159,6 +176,7 @@ The \fIpath\fR or \fItimes\fR argument points to an illegal address. For
.ad
.RS 16n
A signal was caught during the execution of the \fButimes()\fR,
+\fBlutimes()\fR, \fBfutimes()\fR,
\fBfutimesat()\fR, \fBfutimens()\fR, or \fButimensat()\fR functions.
.RE
@@ -270,7 +288,6 @@ length exceeds {\fIPATH_MAX\fR}.
.RE
.SH ATTRIBUTES
-.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -290,6 +307,5 @@ Standard See below.
.LP
For \fButimes()\fR, \fButimensat()\fR and \fBfutimensat()\fR, see \fBstandards\fR(5).
.SH SEE ALSO
-.LP
-\fBfutimens\fR(2), \fBstat\fR(2), \fButime\fR(2), \fBattributes\fR(5),
+fBstat\fR(2), \fButime\fR(2), \fBattributes\fR(5),
\fBfsattr\fR(5), \fBstandards\fR(5)
diff --git a/usr/src/man/man3head/Makefile b/usr/src/man/man3head/Makefile
index fdc94ef4ef..8e1e75e6fb 100644
--- a/usr/src/man/man3head/Makefile
+++ b/usr/src/man/man3head/Makefile
@@ -13,6 +13,7 @@
# Copyright 2011, Richard Lowe
# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
include $(SRC)/Makefile.master
@@ -93,6 +94,7 @@ MANFILES= acct.h.3head \
time.h.3head \
timeb.h.3head \
times.h.3head \
+ timespec.3head \
types.h.3head \
types32.h.3head \
uchar.h.3head \
@@ -273,6 +275,9 @@ MANLINKS += acct.3head \
time.3head \
timeb.3head \
times.3head \
+ timeval.3head \
+ TIMEVAL_TO_TIMESPEC.3head \
+ TIMESPEC_TO_TIMEVAL.3head \
types.3head \
types32.3head \
ucontext.3head \
@@ -451,6 +456,10 @@ tgmath.3head := LINKSRC = tgmath.h.3head
time.3head := LINKSRC = time.h.3head
timeb.3head := LINKSRC = timeb.h.3head
times.3head := LINKSRC = times.h.3head
+timespec.3head := LINKSRC = time.h.3head
+timeval.3head := LINKSRC = timespec.3head
+TIMEVAL_TO_TIMESPEC.3head := LINKSRC = timespec.3head
+TIMESPEC_TO_TIMEVAL.3head := LINKSRC = timespec.3head
types.3head := LINKSRC = types.h.3head
types32.3head := LINKSRC = types32.h.3head
ucontext.3head := LINKSRC = ucontext.h.3head
diff --git a/usr/src/man/man3head/timespec.3head b/usr/src/man/man3head/timespec.3head
new file mode 100644
index 0000000000..54aaab14f5
--- /dev/null
+++ b/usr/src/man/man3head/timespec.3head
@@ -0,0 +1,106 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+.\"
+.Dd Sep 06, 2020
+.Dt timespec 3HEAD
+.Os
+.Sh NAME
+.Nm timespec ,
+.Nm timeval ,
+.Nm TIMESPEC_TO_TIMEVAL ,
+.Nm TIMEVAL_TO_TIMESPEC
+.Nd time structures and conversion
+.Sh SYNOPSIS
+.In sys/time.h
+.Ft void
+.Fo TIMESPEC_TO_TIMEVAL
+.Fa "struct timeval *tv"
+.Fa "const struct timespec *ts"
+.Fc
+.Ft void
+.Fo TIMEVAL_TO_TIMESPEC
+.Fa "const struct timeval *tv"
+.Fa "struct timespec *ts"
+.Fc
+.Sh DESCRIPTION
+The
+.Vt timeval
+and
+.Vt timespec
+structures are declared in the
+.In time.h
+and
+.In sys/time.h
+headers respectively:
+.Bd -literal -offset indent
+typedef struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+} timespec_t;
+
+struct timeval {
+ time_t tv_sec; /* seconds */
+ suseconds_t tv_usec; /* and microseconds */
+};
+.Ed
+.Pp
+In both cases, the
+.Fa tv_sec
+member represents elapsed time in whole seconds.
+The
+.Fa tv_nsec
+and
+.Fa tv_usec
+members represent the rest of the elapsed time in nanoseconds and
+microseconds respectively, depending on the structure.
+.Pp
+The
+.Dv TIMEVAL_TO_TIMESPEC
+macro can be used to convert a
+.Vt struct timeval
+structure to a
+.Vt struct timespec
+structure, while the
+.Dv TIMESPEC_TO_TIMEVAL
+macro works in the opposite direction.
+.Pp
+When converting from a
+.Vt struct timespec
+to a
+.Vt struct timeval
+structure, the
+.Fa tv_nsec
+member is truncated, losing precision.
+When converting from a
+.Vt struct timeval
+to a
+.Vt struct timespec
+structure, the
+.Fa tv_usec
+member is multiplied by 1000 to reach the precision of the target
+structure.
+The
+.Fa tv_sec
+member is always preserved, no matter which conversion is performed.
+.Pp
+Note that the
+.Dv TIMEVAL_TO_TIMESPEC
+and
+.Dv TIMESPEC_TO_TIMEVAL
+macros are non-standard but are commonly found on UNIX and UNIX-like systems.
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT-LEVEL
+.Sy MT-Safe
+.Sh SEE ALSO
+.Xr time.h 3HEAD
diff --git a/usr/src/man/man3lib/libc.3lib b/usr/src/man/man3lib/libc.3lib
index 83df10408b..9bdf613acf 100644
--- a/usr/src/man/man3lib/libc.3lib
+++ b/usr/src/man/man3lib/libc.3lib
@@ -7,7 +7,7 @@
.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with
.\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
.\" Copyright 2011 by Delphix. All rights reserved.
-.TH LIBC 3LIB "Feb 14, 2020"
+.TH LIBC 3LIB "Sep 06, 2020"
.SH NAME
libc \- C library
.SH DESCRIPTION
@@ -261,130 +261,131 @@ l l .
\fBftok\fR \fBftruncate\fR
\fBftrylockfile\fR \fBftw\fR
\fBfunc_to_decimal\fR \fBfunlockfile\fR
-\fBfutimens\fR \fBfutimesat\fR
-\fBfwide\fR \fBfwprintf\fR
-\fBfwrite\fR \fBfwscanf\fR
-\fBgconvert\fR \fBgcvt\fR
-\fBgetacct\fR \fBgetattrat\fR
-\fBgetc\fR \fBgetc_unlocked\fR
-\fBgetchar\fR \fBgetchar_unlocked\fR
-\fBgetcontext\fR \fBgetcpuid\fR
-\fBgetcwd\fR \fBgetdate\fR
-\fBgetdate_err\fR \fBgetdents\fR
-\fBgetdtablesize\fR \fBgetegid\fR
-\fBgetenv\fR \fBgeteuid\fR
-\fBgetexecname\fR \fBgetextmntent\fR
-\fBgetgid\fR \fBgetgrent\fR
-\fBgetgrent_r\fR \fBgetgrgid\fR
-\fBgetgrgid_r\fR \fBgetgrnam\fR
-\fBgetgrnam_r\fR \fBgetgroups\fR
-\fBgethomelgroup\fR \fBgethostid\fR
-\fBgethostname\fR \fBgethrtime\fR
-\fBgethrvtime\fR \fBgetisax\fR
-\fBgetitimer\fR \fBgetloadavg\fR
-\fBgetlogin\fR \fBgetlogin_r\fR
-\fBgetmntany\fR \fBgetmntent\fR
-\fBgetmsg\fR \fBget_nprocs\fR
-\fBget_nprocs_conf\fR \fBgetnetgrent\fR
-\fBgetnetgrent_r\fR \fBgetopt\fR
-\fBgetopt_clip\fR \fBgetopt_long\fR
-\fBgetopt_long_only\fR \fBgetpagesize\fR
-\fBgetpagesizes\fR \fBgetpass\fR
-\fBgetpassphrase\fR \fBgetpeerucred\fR
-\fBgetpflags\fR \fBgetpgid\fR
-\fBgetpgrp\fR \fBgetpid\fR
-\fBgetpmsg\fR \fBgetppid\fR
-\fBgetppriv\fR \fBgetpriority\fR
-\fBgetprogname\fR \fBgetprojid\fR
-\fBgetpw\fR \fBgetpwent\fR
-\fBgetpwent_r\fR \fBgetpwnam\fR
-\fBgetpwnam_r\fR \fBgetpwuid\fR
-\fBgetpwuid_r\fR \fBgetrctl\fR
-\fBgetrlimit\fR \fBgetrusage\fR
-\fBgets\fR \fBgetsid\fR
-\fBgetspent\fR \fBgetspent_r\fR
-\fBgetspnam\fR \fBgetspnam_r\fR
-\fBgetsubopt\fR \fBgettaskid\fR
-\fBgettext\fR \fBgettimeofday\fR
-\fBgettxt\fR \fBgetuid\fR
-\fBgetusershell\fR \fBgetustack\fR
-\fBgetutent\fR \fBgetutid\fR
-\fBgetutline\fR \fBgetutmp\fR
-\fBgetutmpx\fR \fBgetutxent\fR
-\fBgetutxid\fR \fBgetutxline\fR
-\fBgetvfsany\fR \fBgetvfsent\fR
-\fBgetvfsfile\fR \fBgetvfsspec\fR
-\fBgetw\fR \fBgetwc\fR
-\fBgetwc_l\fR \fBgetwchar\fR
-\fBgetwchar_l\fR \fBgetwd\fR
-\fBgetwidth\fR \fBgetws\fR
-\fBgetzoneid\fR \fBgetzoneidbyname\fR
-\fBgetzonenamebyid\fR \fBglob\fR
-\fBglobfree\fR \fBgmtime\fR
-\fBgmtime_r\fR \fBgrantpt\fR
-\fBgsignal\fR \fBhasmntopt\fR
-\fBhcreate\fR \fBhdestroy\fR
-\fBhsearch\fR \fBiconv\fR
-\fBiconv_close\fR \fBiconv_open\fR
-\fBimaxabs\fR \fBimaxdiv\fR
-\fBindex\fR \fBinitgroups\fR
-\fBinitstate\fR \fBinnetgr\fR
-\fBinsque\fR \fBioctl\fR
-\fBis_system_labeled\fR \fBisaexec\fR
-\fBisalnum\fR \fBisalnum_l\fR
-\fBisalpha\fR \fBisalpha_l\fR
-\fBisascii\fR \fBisastream\fR
-\fBisatty\fR \fBisblank\fR
-\fBisblank_l\fR \fBiscntrl\fR
-\fBiscntrl_l\fR \fBisdigit\fR
-\fBisdigit_l\fR \fBisenglish\fR
-\fBisgraph\fR \fBisgraph_l\fR
-\fBisideogram\fR \fBislower\fR
-\fBislower_l\fR \fBisnan\fR
-\fBisnand\fR \fBisnanf\fR
-\fBisnumber\fR \fBisphonogram\fR
-\fBisprint\fR \fBisprint_l\fR
-\fBispunct\fR \fBispunct_l\fR
-\fBissetugid\fR \fBisspace\fR
-\fBisspace_l\fR \fBisspecial\fR
-\fBisupper\fR \fBisupper_l\fR
-\fBiswalnum\fR \fBiswalnum_l\fR
-\fBiswalpha\fR \fBiswalpha_l\fR
-\fBiswblank\fR \fBiswblank_l\fR
-\fBiswcntrl\fR \fBiswcntrl_l\fR
-\fBiswctype\fR \fBiswctype_l\fR
-\fBiswdigit\fR \fBiswdigit_l\fR
-\fBiswideogram\fR \fBiswideogram_l\fR
-\fBiswgraph\fR \fBiswgraph_l\fR
-\fBiswhexnumber\fR \fBiswhexnumber_l\fR
-\fBiswlower\fR \fBiswlower_l\fR
-\fBiswnumber\fR \fBiswnumber_l\fR
-\fBiswphonogram\fR \fBiswphonogram_l\fR
-\fBiswprint\fR \fBiswprint_l\fR
-\fBiswpunct\fR \fBiswpunct_l\fR
-\fBiswspace\fR \fBiswspace_l\fR
-\fBiswspecial\fR \fBiswspecial_l\fR
-\fBiswupper\fR \fBiswupper_l\fR
-\fBiswxdigit\fR \fBiswxdigit_l\fR
-\fBisxdigit\fR \fBisxdigit_l\fR
-\fBjrand48\fR \fBkill\fR
-\fBkillpg\fR \fBl64a\fR
-\fBlabs\fR \fBladd\fR
-\fBlchown\fR \fBlckpwdf\fR
-\fBlcong48\fR \fBldexp\fR
-\fBldivide\fR \fBlexp10\fR
-\fBlfind\fR \fBlfmt\fR
-\fBlink\fR \fBlinkat\fR
-\fBlio_listio\fR \fBllabs\fR
-\fBlldiv\fR \fBllog10\fR
-\fBllseek\fR \fBlltostr\fR
-\fBlocaleconv\fR \fBlocaltime\fR
-\fBlocaltime_r\fR \fBlockf\fR
-\fBlogb\fR \fBlone\fR
-\fBlongjmp\fR \fBlrand48\fR
-\fBlsearch\fR \fBlseek\fR
-\fBlshiftl\fR \fBlstat\fR
-\fBlsub\fR \fBlten\fR
+\fBfutimens\fR \fBfutimes\fR
+\fBfutimesat\fR \fBfwide\fR
+\fBfwprintf\fR \fBfwrite\fR
+\fBfwscanf\fR \fBgconvert\fR
+\fBgcvt\fR \fBgetacct\fR
+\fBgetattrat\fR \fBgetc\fR
+\fBgetc_unlocked\fR \fBgetchar\fR
+\fBgetchar_unlocked\fR \fBgetcontext\fR
+\fBgetcpuid\fR \fBgetcwd\fR
+\fBgetdate\fR \fBgetdate_err\fR
+\fBgetdents\fR \fBgetdtablesize\fR
+\fBgetegid\fR \fBgetenv\fR
+\fBgeteuid\fR \fBgetexecname\fR
+\fBgetextmntent\fR \fBgetgid\fR
+\fBgetgrent\fR \fBgetgrent_r\fR
+\fBgetgrgid\fR \fBgetgrgid_r\fR
+\fBgetgrnam\fR \fBgetgrnam_r\fR
+\fBgetgroups\fR \fBgethomelgroup\fR
+\fBgethostid\fR \fBgethostname\fR
+\fBgethrtime\fR \fBgethrvtime\fR
+\fBgetisax\fR \fBgetitimer\fR
+\fBgetloadavg\fR \fBgetlogin\fR
+\fBgetlogin_r\fR \fBgetmntany\fR
+\fBgetmntent\fR \fBgetmsg\fR
+\fBget_nprocs\fR \fBget_nprocs_conf\fR
+\fBgetnetgrent\fR \fBgetnetgrent_r\fR
+\fBgetopt\fR \fBgetopt_clip\fR
+\fBgetopt_long\fR \fBgetopt_long_only\fR
+\fBgetpagesize\fR \fBgetpagesizes\fR
+\fBgetpass\fR \fBgetpassphrase\fR
+\fBgetpeerucred\fR \fBgetpflags\fR
+\fBgetpgid\fR \fBgetpgrp\fR
+\fBgetpid\fR \fBgetpmsg\fR
+\fBgetppid\fR \fBgetppriv\fR
+\fBgetpriority\fR \fBgetprogname\fR
+\fBgetprojid\fR \fBgetpw\fR
+\fBgetpwent\fR \fBgetpwent_r\fR
+\fBgetpwnam\fR \fBgetpwnam_r\fR
+\fBgetpwuid\fR \fBgetpwuid_r\fR
+\fBgetrctl\fR \fBgetrlimit\fR
+\fBgetrusage\fR \fBgets\fR
+\fBgetsid\fR \fBgetspent\fR
+\fBgetspent_r\fR \fBgetspnam\fR
+\fBgetspnam_r\fR \fBgetsubopt\fR
+\fBgettaskid\fR \fBgettext\fR
+\fBgettimeofday\fR \fBgettxt\fR
+\fBgetuid\fR \fBgetusershell\fR
+\fBgetustack\fR \fBgetutent\fR
+\fBgetutid\fR \fBgetutline\fR
+\fBgetutmp\fR \fBgetutmpx\fR
+\fBgetutxent\fR \fBgetutxid\fR
+\fBgetutxline\fR \fBgetvfsany\fR
+\fBgetvfsent\fR \fBgetvfsfile\fR
+\fBgetvfsspec\fR \fBgetw\fR
+\fBgetwc\fR \fBgetwc_l\fR
+\fBgetwchar\fR \fBgetwchar_l\fR
+\fBgetwd\fR \fBgetwidth\fR
+\fBgetws\fR \fBgetzoneid\fR
+\fBgetzoneidbyname\fR \fBgetzonenamebyid\fR
+\fBglob\fR \fBglobfree\fR
+\fBgmtime\fR \fBgmtime_r\fR
+\fBgrantpt\fR \fBgsignal\fR
+\fBhasmntopt\fR \fBhcreate\fR
+\fBhdestroy\fR \fBhsearch\fR
+\fBiconv\fR \fBiconv_close\fR
+\fBiconv_open\fR \fBimaxabs\fR
+\fBimaxdiv\fR \fBindex\fR
+\fBinitgroups\fR \fBinitstate\fR
+\fBinnetgr\fR \fBinsque\fR
+\fBioctl\fR \fBis_system_labeled\fR
+\fBisaexec\fR \fBisalnum\fR
+\fBisalnum_l\fR \fBisalpha\fR
+\fBisalpha_l\fR \fBisascii\fR
+\fBisastream\fR \fBisatty\fR
+\fBisblank\fR \fBisblank_l\fR
+\fBiscntrl\fR \fBiscntrl_l\fR
+\fBisdigit\fR \fBisdigit_l\fR
+\fBisenglish\fR \fBisgraph\fR
+\fBisgraph_l\fR \fBisideogram\fR
+\fBislower\fR \fBislower_l\fR
+\fBisnan\fR \fBisnand\fR
+\fBisnanf\fR \fBisnumber\fR
+\fBisphonogram\fR \fBisprint\fR
+\fBisprint_l\fR \fBispunct\fR
+\fBispunct_l\fR \fBissetugid\fR
+\fBisspace\fR \fBisspace_l\fR
+\fBisspecial\fR \fBisupper\fR
+\fBisupper_l\fR \fBiswalnum\fR
+\fBiswalnum_l\fR \fBiswalpha\fR
+\fBiswalpha_l\fR \fBiswblank\fR
+\fBiswblank_l\fR \fBiswcntrl\fR
+\fBiswcntrl_l\fR \fBiswctype\fR
+\fBiswctype_l\fR \fBiswdigit\fR
+\fBiswdigit_l\fR \fBiswideogram\fR
+\fBiswideogram_l\fR \fBiswgraph\fR
+\fBiswgraph_l\fR \fBiswhexnumber\fR
+\fBiswhexnumber_l\fR \fBiswlower\fR
+\fBiswlower_l\fR \fBiswnumber\fR
+\fBiswnumber_l\fR \fBiswphonogram\fR
+\fBiswphonogram_l\fR \fBiswprint\fR
+\fBiswprint_l\fR \fBiswpunct\fR
+\fBiswpunct_l\fR \fBiswspace\fR
+\fBiswspace_l\fR \fBiswspecial\fR
+\fBiswspecial_l\fR \fBiswupper\fR
+\fBiswupper_l\fR \fBiswxdigit\fR
+\fBiswxdigit_l\fR \fBisxdigit\fR
+\fBisxdigit_l\fR \fBjrand48\fR
+\fBkill\fR \fBkillpg\fR
+\fBl64a\fR \fBlabs\fR
+\fBladd\fR \fBlchown\fR
+\fBlckpwdf\fR \fBlcong48\fR
+\fBldexp\fR \fBldivide\fR
+\fBlexp10\fR \fBlfind\fR
+\fBlfmt\fR \fBlink\fR
+\fBlinkat\fR \fBlio_listio\fR
+\fBllabs\fR \fBlldiv\fR
+\fBllog10\fR \fBllseek\fR
+\fBlltostr\fR \fBlocaleconv\fR
+\fBlocaltime\fR \fBlocaltime_r\fR
+\fBlockf\fR \fBlogb\fR
+\fBlone\fR \fBlongjmp\fR
+\fBlrand48\fR \fBlsearch\fR
+\fBlseek\fR \fBlshiftl\fR
+\fBlstat\fR \fBlsub\fR
+\fBlten\fR \fBlutimes\fR
\fBlzero\fR \fBmadvise\fR
\fBmakecontext\fR \fBmakeutx\fR
\fBmalloc\fR \fBmblen\fR
diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf
index 8a5436aba7..d9d94487f0 100644
--- a/usr/src/pkg/manifests/system-header.mf
+++ b/usr/src/pkg/manifests/system-header.mf
@@ -28,6 +28,7 @@
# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
# Copyright 2020 Joyent, Inc.
# Copyright 2019 Peter Tribble.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
set name=pkg.fmri value=pkg:/system/header@$(PKGVERS)
@@ -1909,6 +1910,7 @@ file path=usr/share/man/man3head/tgmath.h.3head
file path=usr/share/man/man3head/time.h.3head
file path=usr/share/man/man3head/timeb.h.3head
file path=usr/share/man/man3head/times.h.3head
+file path=usr/share/man/man3head/timespec.3head
file path=usr/share/man/man3head/types.h.3head
file path=usr/share/man/man3head/types32.h.3head
file path=usr/share/man/man3head/uchar.h.3head
@@ -2113,6 +2115,10 @@ link path=usr/share/man/man3head/TAILQ_NEXT.3head target=queue.h.3head
link path=usr/share/man/man3head/TAILQ_PREV.3head target=queue.h.3head
link path=usr/share/man/man3head/TAILQ_REMOVE.3head target=queue.h.3head
link path=usr/share/man/man3head/TAILQ_SWAP.3head target=queue.h.3head
+link path=usr/share/man/man3head/TIMESPEC_TO_TIMEVAL.3head \
+ target=timespec.3head
+link path=usr/share/man/man3head/TIMEVAL_TO_TIMESPEC.3head \
+ target=timespec.3head
link path=usr/share/man/man3head/acct.3head target=acct.h.3head
link path=usr/share/man/man3head/aio.3head target=aio.h.3head
link path=usr/share/man/man3head/ar.3head target=ar.h.3head
@@ -2186,6 +2192,7 @@ link path=usr/share/man/man3head/tgmath.3head target=tgmath.h.3head
link path=usr/share/man/man3head/time.3head target=time.h.3head
link path=usr/share/man/man3head/timeb.3head target=timeb.h.3head
link path=usr/share/man/man3head/times.3head target=times.h.3head
+link path=usr/share/man/man3head/timeval.3head target=timespec.3head
link path=usr/share/man/man3head/types.3head target=types.h.3head
link path=usr/share/man/man3head/types32.3head target=types32.h.3head
link path=usr/share/man/man3head/ucontext.3head target=ucontext.h.3head
diff --git a/usr/src/pkg/manifests/system-kernel.man2.inc b/usr/src/pkg/manifests/system-kernel.man2.inc
index e5e1ace483..6a45a39b55 100644
--- a/usr/src/pkg/manifests/system-kernel.man2.inc
+++ b/usr/src/pkg/manifests/system-kernel.man2.inc
@@ -15,6 +15,7 @@
# Copyright 2013, OmniTI Computer Consulting, Inc.
# Copyright 2017 Peter Tribble
# Copyright 2018, Joyent, Inc.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
file path=usr/share/man/man2/Intro.2
@@ -192,6 +193,7 @@ link path=usr/share/man/man2/fstat.2 target=stat.2
link path=usr/share/man/man2/fstatat.2 target=stat.2
link path=usr/share/man/man2/fstatvfs.2 target=statvfs.2
link path=usr/share/man/man2/futimens.2 target=utimes.2
+link path=usr/share/man/man2/futimes.2 target=utimes.2
link path=usr/share/man/man2/futimesat.2 target=utimes.2
link path=usr/share/man/man2/getaudit_addr.2 target=getaudit.2
link path=usr/share/man/man2/getegid.2 target=getuid.2
@@ -205,9 +207,10 @@ link path=usr/share/man/man2/getprojid.2 target=settaskid.2
link path=usr/share/man/man2/getrctl.2 target=setrctl.2
link path=usr/share/man/man2/gettaskid.2 target=settaskid.2
link path=usr/share/man/man2/intro.2 target=Intro.2
-link path=usr/share/man/man2/linkat.2 target=link.2
link path=usr/share/man/man2/lchown.2 target=chown.2
+link path=usr/share/man/man2/linkat.2 target=link.2
link path=usr/share/man/man2/lstat.2 target=stat.2
+link path=usr/share/man/man2/lutimes.2 target=utimes.2
link path=usr/share/man/man2/mkdirat.2 target=mkdir.2
link path=usr/share/man/man2/mknodat.2 target=mknod.2
link path=usr/share/man/man2/openat.2 target=open.2
diff --git a/usr/src/pkg/manifests/system-test-libctest.mf b/usr/src/pkg/manifests/system-test-libctest.mf
index 659006a358..3145beeadc 100644
--- a/usr/src/pkg/manifests/system-test-libctest.mf
+++ b/usr/src/pkg/manifests/system-test-libctest.mf
@@ -14,6 +14,7 @@
# Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2015 Garrett D'Amore <garrett@damore.org>
# Copyright 2018 Joyent, Inc.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
set name=pkg.fmri value=pkg:/system/test/libctest@$(PKGVERS)
@@ -189,6 +190,8 @@ file path=opt/libc-tests/tests/timespec_get.32 mode=0555
file path=opt/libc-tests/tests/timespec_get.64 mode=0555
file path=opt/libc-tests/tests/uchar.32 mode=0555
file path=opt/libc-tests/tests/uchar.64 mode=0555
+file path=opt/libc-tests/tests/utimes.32 mode=0555
+file path=opt/libc-tests/tests/utimes.64 mode=0555
file path=opt/libc-tests/tests/wcsncasecmp-7344.32 mode=0555
file path=opt/libc-tests/tests/wcsncasecmp-7344.64 mode=0555
file path=opt/libc-tests/tests/wcsncasecmp-7350.32 mode=0555
diff --git a/usr/src/prototypes/prototype.man3x b/usr/src/prototypes/prototype.man3x
index 598315f959..3604b4a0e2 100644
--- a/usr/src/prototypes/prototype.man3x
+++ b/usr/src/prototypes/prototype.man3x
@@ -59,7 +59,7 @@ A Reason why ERRNO1 could occur.
A Reason why ERRNO2 could occur.
.El
.Sh INTERFACE STABILITY
-.\" Indicate the stability per attribute(5). One of:
+.\" Indicate the stability per attributes(5). One of:
.\" .Sy Committed
.\" .Sy Uncommitted
.\" .Sy Volatile
diff --git a/usr/src/test/libc-tests/cfg/symbols/sys_time_h.cfg b/usr/src/test/libc-tests/cfg/symbols/sys_time_h.cfg
index afed10a6bb..8ca9bacb9d 100644
--- a/usr/src/test/libc-tests/cfg/symbols/sys_time_h.cfg
+++ b/usr/src/test/libc-tests/cfg/symbols/sys_time_h.cfg
@@ -11,6 +11,7 @@
#
# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -40,3 +41,16 @@ func | utimes |\
int |\
const char *; const struct timeval [2] |\
sys/time.h | -POSIX+ -XPG3+ SUS+
+
+func | lutimes |\
+ int |\
+ const char *; const struct timeval [2] |\
+ sys/time.h | -ALL
+
+func | futimes |\
+ int |\
+ int; const struct timeval [2] |\
+ sys/time.h | -ALL
+
+define | TIMEVAL_TO_TIMESPEC | | sys/time.h | -ALL
+define | TIMESPEC_TO_TIMEVAL | | sys/time.h | -ALL
diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run
index 0ad4526774..bada7ea85b 100644
--- a/usr/src/test/libc-tests/runfiles/default.run
+++ b/usr/src/test/libc-tests/runfiles/default.run
@@ -13,6 +13,7 @@
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright 2019 Joyent, Inc.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
[DEFAULT]
@@ -124,6 +125,8 @@ timeout = 600
[/opt/libc-tests/tests/timespec_get.64]
[/opt/libc-tests/tests/uchar.32]
[/opt/libc-tests/tests/uchar.64]
+[/opt/libc-tests/tests/utimes.32]
+[/opt/libc-tests/tests/utimes.64]
#
# root privs required for priority changes
diff --git a/usr/src/test/libc-tests/tests/Makefile b/usr/src/test/libc-tests/tests/Makefile
index 0b460ff2f2..54a9a23572 100644
--- a/usr/src/test/libc-tests/tests/Makefile
+++ b/usr/src/test/libc-tests/tests/Makefile
@@ -13,6 +13,7 @@
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright 2015 Garrett D'Amore <garrett@damore.org>
# Copyright 2019 Joyent, Inc.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
SUBDIRS = \
@@ -52,7 +53,8 @@ PROGS = \
wcsncasecmp \
wcsncasecmp-7344 \
wcsncasecmp-7350 \
- uchar
+ uchar \
+ utimes
SCRIPTS = \
quick_exit \
diff --git a/usr/src/test/libc-tests/tests/utimes.c b/usr/src/test/libc-tests/tests/utimes.c
new file mode 100644
index 0000000000..7585289fe6
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/utimes.c
@@ -0,0 +1,521 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+/*
+ * Test the implementation of the various *utimes() and *utimens() functions
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+timespec_t testtimes[] = {
+ {
+ .tv_sec = 1280793678,
+ .tv_nsec = 123456789
+ },
+ {
+ .tv_sec = 1492732800,
+ .tv_nsec = 17
+ },
+ {
+ .tv_sec = 1320796855,
+ .tv_nsec = 9
+ },
+ {
+ .tv_sec = 1498953611,
+ .tv_nsec = 987654321
+ }
+};
+
+enum ttype {
+ UTIMES,
+ LUTIMES,
+ FUTIMES,
+ FUTIMESAT,
+ FUTIMENS,
+ UTIMENSAT
+};
+
+static bool
+compare_times(struct stat *st, bool trunc, timespec_t *atim, timespec_t *mtim,
+ bool invert)
+{
+ bool ret = true;
+
+ if (st->st_atim.tv_sec != atim->tv_sec) {
+ ret = false;
+ } else if (st->st_atim.tv_nsec != (
+ trunc ? atim->tv_nsec / 1000 * 1000 : atim->tv_nsec)) {
+ ret = false;
+ } else if (st->st_mtim.tv_sec != mtim->tv_sec) {
+ ret = false;
+ } else if (st->st_mtim.tv_nsec != (
+ trunc ? mtim->tv_nsec / 1000 * 1000 : mtim->tv_nsec)) {
+ ret = false;
+ }
+
+ if ((!ret && !invert) || (ret && invert)) {
+ printf(" actual atime: %ld.%.9ld\n",
+ st->st_atim.tv_sec, st->st_atim.tv_nsec);
+ printf(" actual mtime: %ld.%.9ld\n",
+ st->st_mtim.tv_sec, st->st_mtim.tv_nsec);
+ }
+
+ return (ret);
+}
+
+static bool
+compare_filetime(char *path, bool trunc, timespec_t *atim, timespec_t *mtim,
+ bool invert)
+{
+ struct stat st;
+
+ if (stat(path, &st) == -1)
+ err(EXIT_FAILURE, "stat %s", path);
+
+ return (compare_times(&st, trunc, atim, mtim, invert));
+}
+
+static bool
+compare_linktime(char *path, bool trunc, timespec_t *atim, timespec_t *mtim,
+ bool invert)
+{
+ struct stat st;
+
+ if (lstat(path, &st) == -1)
+ err(EXIT_FAILURE, "lstat %s", path);
+
+ return (compare_times(&st, trunc, atim, mtim, invert));
+}
+
+static bool
+reset(char *path, timespec_t *atim, timespec_t *mtim)
+{
+ if (utimes(path, NULL) == -1)
+ err(EXIT_FAILURE, "utimes reset");
+ if (compare_filetime(path, true, atim, mtim, true)) {
+ warnx("reset failed");
+ return (false);
+ }
+ return (true);
+}
+
+static bool
+reset_link(char *lpath, timespec_t *atim, timespec_t *mtim)
+{
+ if (lutimes(lpath, NULL) == -1)
+ err(EXIT_FAILURE, "lutimes reset");
+ if (compare_linktime(lpath, true, atim, mtim, true)) {
+ warnx("link reset failed");
+ return (false);
+ }
+ return (true);
+}
+
+static bool
+runtest(enum ttype fn, char *dir, timespec_t *atim, timespec_t *mtim)
+{
+ char path[MAXPATHLEN + 1];
+ char lpath[MAXPATHLEN + 1];
+ struct timespec ts[2];
+ struct timeval tv[2];
+ int fd, lfd, dfd, ret = true;
+
+ ts[0] = *atim;
+ ts[1] = *mtim;
+ TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]);
+ TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]);
+
+ if (snprintf(path, sizeof (path), "%s/file", dir) >= sizeof (path))
+ err(EXIT_FAILURE, "snprintf failed to build file path");
+
+ if ((fd = open(path, O_CREAT, 0644)) == -1)
+ err(EXIT_FAILURE, "open file %s", path);
+
+ if (snprintf(lpath, sizeof (lpath), "%s/link", dir) >= sizeof (path))
+ err(EXIT_FAILURE, "snprintf failed to build link path");
+
+ if (symlink(path, lpath) == -1)
+ err(EXIT_FAILURE, "link(%s)", lpath);
+
+ if ((lfd = open(lpath, O_RDWR)) == -1)
+ err(EXIT_FAILURE, "open link(%s)", lpath);
+
+ if ((dfd = open(dir, O_DIRECTORY|O_RDONLY)) == -1)
+ err(EXIT_FAILURE, "open dir(%s)", dir);
+
+ switch (fn) {
+ case UTIMES:
+ printf("..... utimes()\n");
+
+ if (utimes(path, tv) == -1)
+ err(EXIT_FAILURE, "utimes(%s)", path);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed on file");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (utimes(lpath, tv) == -1)
+ err(EXIT_FAILURE, "utimes(%s), link", lpath);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed on file through link");
+ ret = false;
+ }
+
+ break;
+
+ case LUTIMES:
+ printf("..... lutimes()\n");
+
+ /* Use lutimes() against a plain file */
+ if (lutimes(path, tv) == -1)
+ err(EXIT_FAILURE, "lutimes(%s)", path);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed on file");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* Set the time on the link, not on the target */
+ if (lutimes(lpath, tv) == -1)
+ err(EXIT_FAILURE, "lutimes(%s)", lpath);
+ if (!compare_linktime(lpath, true, atim, mtim, false)) {
+ warnx("link time is incorrect");
+ ret = false;
+ }
+ if (compare_filetime(path, true, atim, mtim, true)) {
+ warnx("target time was updated incorrectly");
+ ret = false;
+ }
+
+ /* Reset the time on the path and link to the current time */
+ if (!reset(path, atim, mtim) || !reset_link(lpath, atim, mtim))
+ ret = false;
+
+ /* and modify the target */
+ if (utimes(path, tv) == -1)
+ err(EXIT_FAILURE, "utimes(%s)", path);
+ /* Now the target should match but the link should not */
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("target time is incorrect");
+ ret = false;
+ }
+ if (compare_linktime(lpath, true, atim, mtim, true)) {
+ warnx("link time was updated incorrectly");
+ ret = false;
+ }
+ break;
+
+ case FUTIMES:
+ printf("..... futimes()\n");
+
+ if (futimes(fd, tv) == -1)
+ err(EXIT_FAILURE, "futimes(%s)", path);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed on file");
+ ret = false;
+ }
+
+ break;
+
+ case FUTIMESAT: {
+ int rfd;
+ printf("..... futimesat()\n");
+
+ /* NULL path, should modify the file for 'fd' */
+ if (futimesat(fd, NULL, tv) == -1)
+ err(EXIT_FAILURE, "futimesat(fd, NULL)");
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed with null path");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* random descriptor, FQ path, descriptor is ignored */
+ if ((rfd = open("/dev/null", O_RDONLY)) == -1)
+ err(EXIT_FAILURE, "open(/dev/null)");
+ if (futimesat(rfd, path, tv) == -1)
+ err(EXIT_FAILURE, "futimesat(dnfd, %s)", path);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed with random descriptor and fq path");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (futimesat(rfd, lpath, tv) == -1)
+ err(EXIT_FAILURE, "futimesat(dnfd, %s), link", lpath);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed through link with "
+ "random descriptor, fq path");
+ ret = false;
+ }
+
+ (void) close(rfd);
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* relative to a directory */
+ if (futimesat(dfd, "file", tv) == -1)
+ err(EXIT_FAILURE, "futimesat(dir, file)", path);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed relative to a directory");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (futimesat(dfd, "link", tv) == -1)
+ err(EXIT_FAILURE, "futimesat(dir, link)");
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed through link relative to a directory");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* AT_FDCWD */
+ if (fchdir(dfd) == -1)
+ err(EXIT_FAILURE, "fchdir(%s)", dir);
+ if (futimesat(AT_FDCWD, "file", tv) == -1)
+ err(EXIT_FAILURE, "futimesat(AT_FDCWD, file)", path);
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed with AT_FDCWD relative");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (futimesat(AT_FDCWD, "link", tv) == -1)
+ err(EXIT_FAILURE, "futimesat(AT_FDCWD, link)");
+ if (!compare_filetime(path, true, atim, mtim, false)) {
+ warnx("failed through link with AT_FDCWD relative");
+ ret = false;
+ }
+
+ break;
+ }
+
+ case FUTIMENS:
+ printf("..... futimens()\n");
+ if (futimens(fd, ts) == -1)
+ err(EXIT_FAILURE, "futimesns(%s)", path);
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed with plain file fd");
+ ret = false;
+ }
+
+ break;
+
+ case UTIMENSAT: {
+ int rfd;
+
+ printf("..... utimensat()\n");
+
+ /* NULL path, expect EFAULT (cf. futimesat()) */
+ if (utimensat(fd, NULL, ts, 0) != -1 || errno != EFAULT) {
+ warnx("null path should return EFAULT but got %d/%s",
+ errno, strerror(errno));
+ ret = false;
+ }
+
+ /* random descriptor, FQ path, descriptor is ignored */
+ if ((rfd = open("/dev/null", O_RDONLY)) == -1)
+ err(EXIT_FAILURE, "open(/dev/null)");
+ if (utimensat(rfd, path, ts, 0) == -1)
+ err(EXIT_FAILURE, "utimensat(dnfd, %s)", path);
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed with random descriptor, fq path");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (utimensat(rfd, lpath, ts, 0) == -1)
+ err(EXIT_FAILURE, "utimensat(dnfd, link %s)", lpath);
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed against link with random descriptor, "
+ "fq path");
+ ret = false;
+ }
+
+ (void) close(rfd);
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* relative to a directory */
+ if (utimensat(dfd, "file", ts, 0) == -1)
+ err(EXIT_FAILURE, "utimensat(dir, file)", path);
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed relative to a directory");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (utimensat(dfd, "link", ts, 0) == -1)
+ err(EXIT_FAILURE, "utimensat(dir, link)", path);
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed through link relative to a directory");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* AT_FDCWD */
+ if (fchdir(dfd) == -1)
+ err(EXIT_FAILURE, "fchdir(%s)", dir);
+ if (utimensat(AT_FDCWD, "file", ts, 0) == -1)
+ err(EXIT_FAILURE, "utimensat(AT_FDCWD, file)");
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed with AT_FDCWD relative");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /* repeat against symbolic link path */
+ if (utimensat(AT_FDCWD, "link", ts, 0) == -1)
+ err(EXIT_FAILURE, "utimensat(AT_FDCWD, link)");
+ if (!compare_filetime(path, false, atim, mtim, false)) {
+ warnx("failed through link with AT_FDCWD relative");
+ ret = false;
+ }
+
+ if (!reset(path, atim, mtim))
+ ret = false;
+
+ /*
+ * Check that none of the above operations have changed the
+ * timestamp on the link.
+ */
+ if (compare_linktime(lpath, true, atim, mtim, true)) {
+ warnx("link timestamp was unexpectedly modified");
+ ret = false;
+ }
+
+ /* Set the time on the link, not on the target */
+ if (utimensat(AT_FDCWD, "link", ts, AT_SYMLINK_NOFOLLOW) == -1)
+ err(EXIT_FAILURE, "utimensat(AT_FDCWD, lflag)");
+ if (!compare_linktime(lpath, false, atim, mtim, false)) {
+ warnx("link time is incorrect");
+ ret = false;
+ }
+ if (compare_filetime(path, false, atim, mtim, true)) {
+ warnx("target time was updated incorrectly");
+ ret = false;
+ }
+ }
+ break;
+ }
+
+ (void) close(dfd);
+ (void) close(lfd);
+ (void) close(fd);
+
+ if (unlink(lpath) == -1)
+ err(EXIT_FAILURE, "unlink(%s)", lpath);
+ if (unlink(path) == -1)
+ err(EXIT_FAILURE, "unlink(%s)", path);
+
+ if (!ret)
+ warnx("Test failed");
+
+ return (ret);
+}
+
+static bool
+runtests(char *dir, timespec_t *atim, timespec_t *mtim)
+{
+ bool ret = true;
+
+ printf("Testing:\n... atime: %ld.%.9ld\n... mtime: %ld.%.9ld\n",
+ atim->tv_sec, atim->tv_nsec, mtim->tv_sec, mtim->tv_nsec);
+
+ if (!runtest(UTIMES, dir, atim, mtim))
+ ret = false;
+ if (!runtest(LUTIMES, dir, atim, mtim))
+ ret = false;
+ if (!runtest(FUTIMES, dir, atim, mtim))
+ ret = false;
+ if (!runtest(FUTIMESAT, dir, atim, mtim))
+ ret = false;
+ if (!runtest(FUTIMENS, dir, atim, mtim))
+ ret = false;
+ if (!runtest(UTIMENSAT, dir, atim, mtim))
+ ret = false;
+
+ return (ret);
+}
+
+int
+main(void)
+{
+ char dir[] = "/tmp/utimes.XXXXXX";
+ int ret = EXIT_SUCCESS;
+ int i;
+
+ if (mkdtemp(dir) == NULL)
+ err(EXIT_FAILURE, "failed to create temporary directory");
+
+ for (i = 0; i < ARRAY_SIZE(testtimes); i += 2) {
+ if (!runtests(dir, &testtimes[i], &testtimes[i + 1]))
+ ret = EXIT_FAILURE;
+ }
+
+ /*
+ * Some tests will have changed directory into 'dir' to test the
+ * AT_FDCWD case. Change back to / to avoid EBUSY when removing dir.
+ */
+ if (chdir("/") == -1)
+ err(EXIT_FAILURE, "chdir(/)");
+ if (rmdir(dir) == -1)
+ err(EXIT_FAILURE, "rmdir %s", dir);
+
+ return (ret);
+}
diff --git a/usr/src/uts/common/sys/time.h b/usr/src/uts/common/sys/time.h
index 8a36f622c3..8ec74d4ecd 100644
--- a/usr/src/uts/common/sys/time.h
+++ b/usr/src/uts/common/sys/time.h
@@ -15,6 +15,8 @@
* Use is subject to license terms.
*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -356,14 +358,14 @@ extern todinfo_t utc_to_tod(time_t);
extern time_t tod_to_utc(todinfo_t);
extern int hr_clock_lock(void);
extern void hr_clock_unlock(int);
-extern hrtime_t gethrtime(void);
-extern hrtime_t gethrtime_unscaled(void);
+extern hrtime_t gethrtime(void);
+extern hrtime_t gethrtime_unscaled(void);
extern hrtime_t gethrtime_max(void);
extern hrtime_t gethrtime_waitfree(void);
extern void scalehrtime(hrtime_t *);
extern uint64_t unscalehrtime(hrtime_t);
-extern void gethrestime(timespec_t *);
-extern time_t gethrestime_sec(void);
+extern void gethrestime(timespec_t *);
+extern time_t gethrestime_sec(void);
extern void gethrestime_lasttick(timespec_t *);
extern void hrt2ts(hrtime_t, timestruc_t *);
extern hrtime_t ts2hrt(const timestruc_t *);
@@ -399,6 +401,7 @@ int futimesat(int, const char *, const struct timeval *);
int getitimer(int, struct itimerval *);
int utimes(const char *, const struct timeval *);
+
#if defined(_XPG4_2)
int setitimer(int, const struct itimerval *_RESTRICT_KYWD,
struct itimerval *_RESTRICT_KYWD);
@@ -409,6 +412,22 @@ int setitimer(int, struct itimerval *_RESTRICT_KYWD,
#endif /* !defined(_KERNEL) ... defined(_XPG4_2) */
+#if !defined(_KERNEL) && !defined(_STRICT_SYMBOLS)
+int futimes(int, const struct timeval *);
+int lutimes(const char *, const struct timeval *);
+
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+
+#endif /* !defined(_KERNEL) && !defined(_STRICT_SYMBOLS) */
+
/*
* gettimeofday() and settimeofday() were included in SVr4 due to their
* common use in BSD based applications. They were to be included exactly