aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/ln/symlink.77
-rw-r--r--lib/libc/include/libc_private.h4
-rw-r--r--lib/libc/sys/Makefile.inc6
-rw-r--r--lib/libc/sys/Symbol.map2
-rw-r--r--lib/libc/sys/futimens.c97
-rw-r--r--lib/libc/sys/utimensat.2292
-rw-r--r--lib/libc/sys/utimensat.c109
-rw-r--r--share/man/man4/rights.48
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c43
-rw-r--r--sys/compat/freebsd32/syscalls.master5
-rw-r--r--sys/kern/capabilities.conf4
-rw-r--r--sys/kern/syscalls.master5
-rw-r--r--sys/kern/vfs_syscalls.c126
-rw-r--r--sys/sys/capsicum.h4
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/stat.h8
-rw-r--r--sys/sys/syscallsubr.h5
-rw-r--r--usr.bin/kdump/kdump.c1
18 files changed, 717 insertions, 11 deletions
diff --git a/bin/ln/symlink.7 b/bin/ln/symlink.7
index 6aba773db7e5..821a3128c914 100644
--- a/bin/ln/symlink.7
+++ b/bin/ln/symlink.7
@@ -29,7 +29,7 @@
.\" @(#)symlink.7 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd December 29, 2014
+.Dd January 23, 2015
.Dt SYMLINK 7
.Os
.Sh NAME
@@ -147,9 +147,10 @@ unless given the
.Dv AT_SYMLINK_NOFOLLOW
flag:
.Xr fchmodat 2 ,
-.Xr fchownat 2
+.Xr fchownat 2 ,
+.Xr fstatat 2
and
-.Xr fstatat 2 .
+.Xr utimensat 2 .
.Pp
The owner and group of an existing symbolic link can be changed by
means of the
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 347b46305d4b..bfcd3d060e96 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -357,6 +357,10 @@ int __libc_system(const char *);
int __libc_tcdrain(int);
int __fcntl_compat(int fd, int cmd, ...);
+int __sys_futimens(int fd, const struct timespec *times) __hidden;
+int __sys_utimensat(int fd, const char *path,
+ const struct timespec *times, int flag) __hidden;
+
/* execve() with PATH processing to implement posix_spawnp() */
int _execvpe(const char *, char * const *, char * const *);
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 0a3c13f8e3b1..e8ec58e7a088 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -38,6 +38,10 @@ SRCS+= ${SYSCALL_COMPAT_SRCS}
NOASM+= ${SYSCALL_COMPAT_SRCS:S/.c/.o/}
.endif
+SRCS+= futimens.c utimensat.c
+NOASM+= futimens.o utimensat.o
+PSEUDO+= _futimens.o _utimensat.o
+
INTERPOSED = \
accept \
accept4 \
@@ -310,6 +314,7 @@ MAN+= sctp_generic_recvmsg.2 \
umask.2 \
undelete.2 \
unlink.2 \
+ utimensat.2 \
utimes.2 \
utrace.2 \
uuidgen.2 \
@@ -442,6 +447,7 @@ MLINKS+=timer_settime.2 timer_getoverrun.2 \
timer_settime.2 timer_gettime.2
MLINKS+=truncate.2 ftruncate.2
MLINKS+=unlink.2 unlinkat.2
+MLINKS+=utimensat.2 futimens.2
MLINKS+=utimes.2 futimes.2 \
utimes.2 futimesat.2 \
utimes.2 lutimes.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index f1f57ba9fb79..194aa5bf0999 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -397,7 +397,9 @@ FBSD_1.3 {
};
FBSD_1.4 {
+ futimens;
ppoll;
+ utimensat;
};
FBSDprivate_1.0 {
diff --git a/lib/libc/sys/futimens.c b/lib/libc/sys/futimens.c
new file mode 100644
index 000000000000..2014cc5cecf3
--- /dev/null
+++ b/lib/libc/sys/futimens.c
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2015 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int
+futimens(int fd, const struct timespec times[2])
+{
+ struct timeval now, tv[2], *tvp;
+ struct stat sb;
+
+ if (__getosreldate() >= 1100056)
+ return (__sys_futimens(fd, times));
+
+ if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
+ times[1].tv_nsec == UTIME_NOW))
+ tvp = NULL;
+ else if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ else {
+ if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
+ times[0].tv_nsec != UTIME_NOW &&
+ times[0].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
+ times[1].tv_nsec != UTIME_NOW &&
+ times[1].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ tv[0].tv_sec = times[0].tv_sec;
+ tv[0].tv_usec = times[0].tv_nsec / 1000;
+ tv[1].tv_sec = times[1].tv_sec;
+ tv[1].tv_usec = times[1].tv_nsec / 1000;
+ tvp = tv;
+ if (times[0].tv_nsec == UTIME_OMIT ||
+ times[1].tv_nsec == UTIME_OMIT) {
+ if (_fstat(fd, &sb) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_OMIT) {
+ tv[0].tv_sec = sb.st_atim.tv_sec;
+ tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
+ }
+ if (times[1].tv_nsec == UTIME_OMIT) {
+ tv[1].tv_sec = sb.st_mtim.tv_sec;
+ tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
+ }
+ }
+ if (times[0].tv_nsec == UTIME_NOW ||
+ times[1].tv_nsec == UTIME_NOW) {
+ if (gettimeofday(&now, NULL) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_NOW)
+ tv[0] = now;
+ if (times[1].tv_nsec == UTIME_NOW)
+ tv[1] = now;
+ }
+ }
+ return (futimes(fd, tvp));
+}
diff --git a/lib/libc/sys/utimensat.2 b/lib/libc/sys/utimensat.2
new file mode 100644
index 000000000000..0f397c6a99aa
--- /dev/null
+++ b/lib/libc/sys/utimensat.2
@@ -0,0 +1,292 @@
+.\" $NetBSD: utimes.2,v 1.13 1999/03/22 19:45:11 garbled Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2012, Jilles Tjoelker
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 23, 2015
+.Dt UTIMENSAT 2
+.Os
+.Sh NAME
+.Nm futimens ,
+.Nm utimensat
+.Nd set file access and modification times
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft int
+.Fn futimens "int fd" "const struct timespec times[2]"
+.Ft int
+.Fo utimensat
+.Fa "int fd"
+.Fa "const char *path"
+.Fa "const struct timespec times[2]"
+.Fa "int flag"
+.Fc
+.Sh DESCRIPTION
+The access and modification times of the file named by
+.Fa path
+or referenced by
+.Fa fd
+are changed as specified by the argument
+.Fa times .
+The inode-change-time of the file is set to the current time.
+.Pp
+If
+.Fa path
+specifies a relative path,
+it is relative to the current working directory if
+.Fa fd
+is
+.Dv AT_FDCWD
+and otherwise relative to the directory associated with the file descriptor
+.Fa fd .
+.Pp
+The
+.Va tv_nsec
+field of a
+.Vt timespec
+structure
+can be set to the special value
+.Dv UTIME_NOW
+to set the current time, or to
+.Dv UTIME_OMIT
+to leave the time unchanged.
+In either case, the
+.Va tv_sec
+field is ignored.
+.Pp
+If
+.Fa times
+is
+.No non- Ns Dv NULL ,
+it is assumed to point to an array of two timespec structures.
+The access time is set to the value of the first element, and the
+modification time is set to the value of the second element.
+For file systems that support file birth (creation) times (such as
+.Dv UFS2 ) ,
+the birth time will be set to the value of the second element
+if the second element is older than the currently set birth time.
+To set both a birth time and a modification time,
+two calls are required; the first to set the birth time
+and the second to set the (presumably newer) modification time.
+Ideally a new system call will be added that allows the setting
+of all three times at once.
+If
+.Fa times
+is
+.Dv NULL ,
+this is equivalent to passing
+a pointer to an array of two timespec structures
+with both
+.Va tv_nsec
+fields set to
+.Dv UTIME_NOW .
+.Pp
+If both
+.Va tv_nsec
+fields are
+.Dv UTIME_OMIT ,
+the timestamps remain unchanged and
+no permissions are needed for the file itself,
+although search permissions may be required for the path prefix.
+The call may or may not succeed if the named file does not exist.
+.Pp
+If both
+.Va tv_nsec
+fields are
+.Dv UTIME_NOW ,
+the caller must be the owner of the file, have permission to
+write the file, or be the super-user.
+.Pp
+For all other values of the timestamps,
+the caller must be the owner of the file or be the super-user.
+.Pp
+The values for the
+.Fa flag
+argument of the
+.Fn utimensat
+system call
+are constructed by a bitwise-inclusive OR of flags from the following list,
+defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, the symbolic link's times are changed.
+By default,
+.Fn utimensat
+changes the times of the file referenced by the symbolic link.
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh COMPATIBILITY
+If the running kernel does not support this system call,
+a wrapper emulates it using
+.Xr fstatat 2 ,
+.Xr futimesat 2
+and
+.Xr lutimes 2 .
+As a result, timestamps will be rounded down to the nearest microsecond,
+.Dv UTIME_OMIT
+is not atomic and
+.Dv AT_SYMLINK_NOFOLLOW
+is not available with a path relative to a file descriptor.
+.Sh ERRORS
+These system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The
+.Fa times
+argument is
+.Dv NULL ,
+or both
+.Va tv_nsec
+values are
+.Dv UTIME_NOW ,
+and the effective user ID of the process does not
+match the owner of the file, and is not the super-user, and write
+access is denied.
+.It Bq Er EFAULT
+The
+.Fa times
+argument
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+The
+.Va tv_usec
+component of at least one of the values specified by the
+.Fa times
+argument has a value less than 0 or greater than 999999.
+.It Bq Er EIO
+An I/O error occurred while reading or writing the affected inode.
+.It Bq Er EPERM
+The
+.Fa times
+argument is not
+.Dv NULL
+nor are both
+.Va tv_nsec
+values
+.Dv UTIME_NOW ,
+nor are both
+.Va tv_nsec
+values
+.Dv UTIME_OMIT
+and the calling process's effective user ID
+does not match the owner of the file and is not the super-user.
+.It Bq Er EPERM
+The named file has its immutable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EROFS
+The file system containing the file is mounted read-only.
+.El
+.Pp
+The
+.Fn futimens
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+does not refer to a valid descriptor.
+.El
+.Pp
+The
+.Fn utimensat
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded
+.Dv NAME_MAX
+characters, or an entire path name exceeded
+.Dv PATH_MAX
+characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.It Bq Er ENOTSUP
+The running kernel does not support this system call and
+.Dv AT_SYMLINK_NOFOLLOW
+is used with a path relative to a file descriptor.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr stat 2 ,
+.Xr symlink 2 ,
+.Xr utimes 2 ,
+.Xr utime 3 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn futimens
+and
+.Fn utimensat
+system calls are expected to conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn futimens
+and
+.Fn utimensat
+system calls appeared in
+.Fx 11.0 .
diff --git a/lib/libc/sys/utimensat.c b/lib/libc/sys/utimensat.c
new file mode 100644
index 000000000000..67d19cb2f9ba
--- /dev/null
+++ b/lib/libc/sys/utimensat.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2015 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int
+utimensat(int fd, const char *path, const struct timespec times[2], int flag)
+{
+ struct timeval now, tv[2], *tvp;
+ struct stat sb;
+
+ if (__getosreldate() >= 1100056)
+ return (__sys_utimensat(fd, path, times, flag));
+
+ if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
+ times[1].tv_nsec == UTIME_NOW))
+ tvp = NULL;
+ else if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ else {
+ if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
+ times[0].tv_nsec != UTIME_NOW &&
+ times[0].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
+ times[1].tv_nsec != UTIME_NOW &&
+ times[1].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ tv[0].tv_sec = times[0].tv_sec;
+ tv[0].tv_usec = times[0].tv_nsec / 1000;
+ tv[1].tv_sec = times[1].tv_sec;
+ tv[1].tv_usec = times[1].tv_nsec / 1000;
+ tvp = tv;
+ if (times[0].tv_nsec == UTIME_OMIT ||
+ times[1].tv_nsec == UTIME_OMIT) {
+ if (fstatat(fd, path, &sb, flag) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_OMIT) {
+ tv[0].tv_sec = sb.st_atim.tv_sec;
+ tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
+ }
+ if (times[1].tv_nsec == UTIME_OMIT) {
+ tv[1].tv_sec = sb.st_mtim.tv_sec;
+ tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
+ }
+ }
+ if (times[0].tv_nsec == UTIME_NOW ||
+ times[1].tv_nsec == UTIME_NOW) {
+ if (gettimeofday(&now, NULL) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_NOW)
+ tv[0] = now;
+ if (times[1].tv_nsec == UTIME_NOW)
+ tv[1] = now;
+ }
+ }
+ if ((flag & AT_SYMLINK_NOFOLLOW) == 0)
+ return (futimesat(fd, path, tvp));
+ else if ((flag & AT_SYMLINK_NOFOLLOW) != 0 &&
+ (fd == AT_FDCWD || path[0] == '/'))
+ return (lutimes(path, tvp));
+ else {
+ errno = ENOTSUP;
+ return (-1);
+ }
+}
diff --git a/share/man/man4/rights.4 b/share/man/man4/rights.4
index 476b15bad1d4..16025c179e65 100644
--- a/share/man/man4/rights.4
+++ b/share/man/man4/rights.4
@@ -32,7 +32,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 23, 2013
+.Dd January 23, 2015
.Dt RIGHTS 4
.Os
.Sh NAME
@@ -272,9 +272,13 @@ with the
flag.
.It Dv CAP_FUTIMES
Permit
-.Xr futimes 2
+.Xr futimens 2
and
+.Xr futimes 2 ,
+and permit
.Xr futimesat 2
+and
+.Xr utimensat 2
if the
.Dv CAP_LOOKUP
right is also present.
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index ffea28371043..a72612b53c1c 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1300,6 +1300,49 @@ freebsd32_futimesat(struct thread *td, struct freebsd32_futimesat_args *uap)
}
int
+freebsd32_futimens(struct thread *td, struct freebsd32_futimens_args *uap)
+{
+ struct timespec32 ts32[2];
+ struct timespec ts[2], *tsp;
+ int error;
+
+ if (uap->times != NULL) {
+ error = copyin(uap->times, ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32[0], ts[0], tv_sec);
+ CP(ts32[0], ts[0], tv_nsec);
+ CP(ts32[1], ts[1], tv_sec);
+ CP(ts32[1], ts[1], tv_nsec);
+ tsp = ts;
+ } else
+ tsp = NULL;
+ return (kern_futimens(td, uap->fd, tsp, UIO_SYSSPACE));
+}
+
+int
+freebsd32_utimensat(struct thread *td, struct freebsd32_utimensat_args *uap)
+{
+ struct timespec32 ts32[2];
+ struct timespec ts[2], *tsp;
+ int error;
+
+ if (uap->times != NULL) {
+ error = copyin(uap->times, ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32[0], ts[0], tv_sec);
+ CP(ts32[0], ts[0], tv_nsec);
+ CP(ts32[1], ts[1], tv_sec);
+ CP(ts32[1], ts[1], tv_nsec);
+ tsp = ts;
+ } else
+ tsp = NULL;
+ return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE,
+ tsp, UIO_SYSSPACE, uap->flag));
+}
+
+int
freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
{
struct timeval32 tv32;
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index ce655bcfa581..91d1727a7f98 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -1069,3 +1069,8 @@
545 AUE_POLL STD { int freebsd32_ppoll(struct pollfd *fds, \
u_int nfds, const struct timespec32 *ts, \
const sigset_t *set); }
+546 AUE_FUTIMES STD { int freebsd32_futimens(int fd, \
+ struct timespec *times); }
+547 AUE_FUTIMESAT STD { int freebsd32_utimensat(int fd, \
+ char *path, \
+ struct timespec *times, int flag); }
diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf
index f7a46aebce2c..d0ea97c4e831 100644
--- a/sys/kern/capabilities.conf
+++ b/sys/kern/capabilities.conf
@@ -220,8 +220,9 @@ fsync
ftruncate
##
-## Allow futimes(2), subject to capability rights.
+## Allow futimens(2) and futimes(2), subject to capability rights.
##
+futimens
futimes
##
@@ -453,6 +454,7 @@ readlinkat
renameat
symlinkat
unlinkat
+utimensat
##
## Allow entry into open(2). This system call will fail, since access to the
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 089896b73751..09d38d40101a 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -983,5 +983,10 @@
545 AUE_POLL STD { int ppoll(struct pollfd *fds, u_int nfds, \
const struct timespec *ts, \
const sigset_t *set); }
+546 AUE_FUTIMES STD { int futimens(int fd, \
+ struct timespec *times); }
+547 AUE_FUTIMESAT STD { int utimensat(int fd, \
+ char *path, \
+ struct timespec *times, int flag); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 3105c2f4bcd5..0f248199d0d4 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -95,10 +95,12 @@ SDT_PROBE_DEFINE2(vfs, , stat, mode, "char *", "int");
SDT_PROBE_DEFINE2(vfs, , stat, reg, "char *", "int");
static int chroot_refuse_vdir_fds(struct filedesc *fdp);
-static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
static int kern_chflagsat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, u_long flags, int atflag);
static int setfflags(struct thread *td, struct vnode *, u_long);
+static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
+static int getutimens(const struct timespec *, enum uio_seg,
+ struct timespec *, int *);
static int setutimes(struct thread *td, struct vnode *,
const struct timespec *, int, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
@@ -3007,7 +3009,53 @@ getutimes(usrtvp, tvpseg, tsp)
}
/*
- * Common implementation code for utimes(), lutimes(), and futimes().
+ * Common implementation code for futimens(), utimensat().
+ */
+#define UTIMENS_NULL 0x1
+#define UTIMENS_EXIT 0x2
+static int
+getutimens(const struct timespec *usrtsp, enum uio_seg tspseg,
+ struct timespec *tsp, int *retflags)
+{
+ struct timespec tsnow;
+ int error;
+
+ vfs_timestamp(&tsnow);
+ *retflags = 0;
+ if (usrtsp == NULL) {
+ tsp[0] = tsnow;
+ tsp[1] = tsnow;
+ *retflags |= UTIMENS_NULL;
+ return (0);
+ }
+ if (tspseg == UIO_SYSSPACE) {
+ tsp[0] = usrtsp[0];
+ tsp[1] = usrtsp[1];
+ } else if ((error = copyin(usrtsp, tsp, sizeof(*tsp) * 2)) != 0)
+ return (error);
+ if (tsp[0].tv_nsec == UTIME_OMIT && tsp[1].tv_nsec == UTIME_OMIT)
+ *retflags |= UTIMENS_EXIT;
+ if (tsp[0].tv_nsec == UTIME_NOW && tsp[1].tv_nsec == UTIME_NOW)
+ *retflags |= UTIMENS_NULL;
+ if (tsp[0].tv_nsec == UTIME_OMIT)
+ tsp[0].tv_sec = VNOVAL;
+ else if (tsp[0].tv_nsec == UTIME_NOW)
+ tsp[0] = tsnow;
+ else if (tsp[0].tv_nsec < 0 || tsp[0].tv_nsec >= 1000000000L)
+ return (EINVAL);
+ if (tsp[1].tv_nsec == UTIME_OMIT)
+ tsp[1].tv_sec = VNOVAL;
+ else if (tsp[1].tv_nsec == UTIME_NOW)
+ tsp[1] = tsnow;
+ else if (tsp[1].tv_nsec < 0 || tsp[1].tv_nsec >= 1000000000L)
+ return (EINVAL);
+
+ return (0);
+}
+
+/*
+ * Common implementation code for utimes(), lutimes(), futimes(), futimens(),
+ * and utimensat().
*/
static int
setutimes(td, vp, ts, numtimes, nullflag)
@@ -3196,6 +3244,80 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr,
return (error);
}
+int
+sys_futimens(struct thread *td, struct futimens_args *uap)
+{
+
+ return (kern_futimens(td, uap->fd, uap->times, UIO_USERSPACE));
+}
+
+int
+kern_futimens(struct thread *td, int fd, struct timespec *tptr,
+ enum uio_seg tptrseg)
+{
+ struct timespec ts[2];
+ struct file *fp;
+ cap_rights_t rights;
+ int error, flags;
+
+ AUDIT_ARG_FD(fd);
+ error = getutimens(tptr, tptrseg, ts, &flags);
+ if (error != 0)
+ return (error);
+ if (flags & UTIMENS_EXIT)
+ return (0);
+ error = getvnode(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_FUTIMES), &fp);
+ if (error != 0)
+ return (error);
+#ifdef AUDIT
+ vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
+ AUDIT_ARG_VNODE1(fp->f_vnode);
+ VOP_UNLOCK(fp->f_vnode, 0);
+#endif
+ error = setutimes(td, fp->f_vnode, ts, 2, flags & UTIMENS_NULL);
+ fdrop(fp, td);
+ return (error);
+}
+
+int
+sys_utimensat(struct thread *td, struct utimensat_args *uap)
+{
+
+ return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE,
+ uap->times, UIO_USERSPACE, uap->flag));
+}
+
+int
+kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
+ struct timespec *tptr, enum uio_seg tptrseg, int flag)
+{
+ struct nameidata nd;
+ struct timespec ts[2];
+ int error, flags;
+
+ if (flag & ~AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+
+ if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0)
+ return (error);
+ NDINIT_AT(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
+ FOLLOW) | AUDITVNODE1, pathseg, path, fd, td);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ /*
+ * We are allowed to call namei() regardless of 2xUTIME_OMIT.
+ * POSIX states:
+ * "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected."
+ * "Search permission is denied by a component of the path prefix."
+ */
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if ((flags & UTIMENS_EXIT) == 0)
+ error = setutimes(td, nd.ni_vp, ts, 2, flags & UTIMENS_NULL);
+ vrele(nd.ni_vp);
+ return (error);
+}
+
/*
* Truncate a file given its path name.
*/
diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h
index de113c62fefc..8502a967498a 100644
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -146,9 +146,9 @@
#define CAP_FSTATAT (CAP_FSTAT | CAP_LOOKUP)
/* Allows for fstatfs(2). */
#define CAP_FSTATFS CAPRIGHT(0, 0x0000000000100000ULL)
-/* Allows for futimes(2). */
+/* Allows for futimens(2) and futimes(2). */
#define CAP_FUTIMES CAPRIGHT(0, 0x0000000000200000ULL)
-/* Allows for futimes(2) and futimesat(2). */
+/* Allows for futimens(2), futimes(2), futimesat(2) and utimensat(2). */
#define CAP_FUTIMESAT (CAP_FUTIMES | CAP_LOOKUP)
/* Allows for linkat(2) and renameat(2) (destination directory descriptor). */
#define CAP_LINKAT (CAP_LOOKUP | 0x0000000000400000ULL)
diff --git a/sys/sys/param.h b/sys/sys/param.h
index bf59b0bf7226..eea93c957abd 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1100055 /* Master, propagated to newvers */
+#define __FreeBSD_version 1100056 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/stat.h b/sys/sys/stat.h
index 13dea2dc72b9..7a4370d64a27 100644
--- a/sys/sys/stat.h
+++ b/sys/sys/stat.h
@@ -307,6 +307,11 @@ struct nstat {
#endif /* __BSD_VISIBLE */
+#if __POSIX_VISIBLE >= 200809
+#define UTIME_NOW -1
+#define UTIME_OMIT -2
+#endif
+
#ifndef _KERNEL
__BEGIN_DECLS
#if __BSD_VISIBLE
@@ -322,6 +327,9 @@ int fchmod(int, mode_t);
#endif
#if __POSIX_VISIBLE >= 200809
int fchmodat(int, const char *, mode_t, int);
+int futimens(int fd, const struct timespec times[2]);
+int utimensat(int fd, const char *path, const struct timespec times[2],
+ int flag);
#endif
int fstat(int, struct stat *);
#if __BSD_VISIBLE
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index f4131a48032b..cb6d4e36cc90 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -99,6 +99,8 @@ int kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
int kern_ftruncate(struct thread *td, int fd, off_t length);
int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg);
+int kern_futimens(struct thread *td, int fd, struct timespec *tptr,
+ enum uio_seg tptrseg);
int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
long *basep, ssize_t *residp, enum uio_seg bufseg);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
@@ -220,6 +222,9 @@ int kern_unlinkat(struct thread *td, int fd, char *path,
enum uio_seg pathseg, ino_t oldinum);
int kern_utimesat(struct thread *td, int fd, char *path,
enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
+int kern_utimensat(struct thread *td, int fd, char *path,
+ enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg,
+ int follow);
int kern_wait(struct thread *td, pid_t pid, int *status, int options,
struct rusage *rup);
int kern_wait6(struct thread *td, enum idtype idtype, id_t id, int *status,
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index ad29bfde74c0..0daf7373cd19 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -714,6 +714,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int flags)
case SYS_readlinkat:
case SYS_renameat:
case SYS_unlinkat:
+ case SYS_utimensat:
putchar('(');
atfdname(*ip, decimal);
c = ',';