Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Jan 2015 21:07:09 +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: r277610 - in head: bin/ln lib/libc/include lib/libc/sys share/man/man4 sys/compat/freebsd32 sys/kern sys/sys usr.bin/kdump
Message-ID:  <201501232107.t0NL79a8099736@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Fri Jan 23 21:07:08 2015
New Revision: 277610
URL: https://svnweb.freebsd.org/changeset/base/277610

Log:
  Add futimens and utimensat system calls.
  
  The core kernel part is patch file utimes.2008.4.diff from
  pluknet@FreeBSD.org. I updated the code for API changes, added the manual
  page and added compatibility code for old kernels. There is also audit and
  Capsicum support.
  
  A new UTIME_* constant might allow setting birthtimes in future.
  
  Differential Revision:	https://reviews.freebsd.org/D1426
  Submitted by:	pluknet (partially)
  Reviewed by:	delphij, pluknet, rwatson
  Relnotes:	yes

Added:
  head/lib/libc/sys/futimens.c   (contents, props changed)
  head/lib/libc/sys/utimensat.2   (contents, props changed)
  head/lib/libc/sys/utimensat.c   (contents, props changed)
Modified:
  head/bin/ln/symlink.7
  head/lib/libc/include/libc_private.h
  head/lib/libc/sys/Makefile.inc
  head/lib/libc/sys/Symbol.map
  head/share/man/man4/rights.4
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/compat/freebsd32/syscalls.master
  head/sys/kern/capabilities.conf
  head/sys/kern/syscalls.master
  head/sys/kern/vfs_syscalls.c
  head/sys/sys/capsicum.h
  head/sys/sys/param.h
  head/sys/sys/stat.h
  head/sys/sys/syscallsubr.h
  head/usr.bin/kdump/kdump.c

Modified: head/bin/ln/symlink.7
==============================================================================
--- head/bin/ln/symlink.7	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/bin/ln/symlink.7	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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

Modified: head/lib/libc/include/libc_private.h
==============================================================================
--- head/lib/libc/include/libc_private.h	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/lib/libc/include/libc_private.h	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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 *);
 

Modified: head/lib/libc/sys/Makefile.inc
==============================================================================
--- head/lib/libc/sys/Makefile.inc	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/lib/libc/sys/Makefile.inc	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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
 	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

Modified: head/lib/libc/sys/Symbol.map
==============================================================================
--- head/lib/libc/sys/Symbol.map	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/lib/libc/sys/Symbol.map	Fri Jan 23 21:07:08 2015	(r277610)
@@ -397,7 +397,9 @@ FBSD_1.3 {
 };
 
 FBSD_1.4 {
+	futimens;
 	ppoll;
+	utimensat;
 };
 
 FBSDprivate_1.0 {

Added: head/lib/libc/sys/futimens.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/sys/futimens.c	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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));
+}

Added: head/lib/libc/sys/utimensat.2
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/sys/utimensat.2	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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 .

Added: head/lib/libc/sys/utimensat.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/sys/utimensat.c	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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);
+	}
+}

Modified: head/share/man/man4/rights.4
==============================================================================
--- head/share/man/man4/rights.4	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/share/man/man4/rights.4	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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.

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Fri Jan 23 21:07:08 2015	(r277610)
@@ -1300,6 +1300,49 @@ freebsd32_futimesat(struct thread *td, s
 }
 
 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;

Modified: head/sys/compat/freebsd32/syscalls.master
==============================================================================
--- head/sys/compat/freebsd32/syscalls.master	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/compat/freebsd32/syscalls.master	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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); }

Modified: head/sys/kern/capabilities.conf
==============================================================================
--- head/sys/kern/capabilities.conf	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/kern/capabilities.conf	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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

Modified: head/sys/kern/syscalls.master
==============================================================================
--- head/sys/kern/syscalls.master	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/kern/syscalls.master	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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

Modified: head/sys/kern/vfs_syscalls.c
==============================================================================
--- head/sys/kern/vfs_syscalls.c	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/kern/vfs_syscalls.c	Fri Jan 23 21:07:08 2015	(r277610)
@@ -95,10 +95,12 @@ SDT_PROBE_DEFINE2(vfs, , stat, mode, "ch
 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, 
 	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.
  */

Modified: head/sys/sys/capsicum.h
==============================================================================
--- head/sys/sys/capsicum.h	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/sys/capsicum.h	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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)

Modified: head/sys/sys/param.h
==============================================================================
--- head/sys/sys/param.h	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/sys/param.h	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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,

Modified: head/sys/sys/stat.h
==============================================================================
--- head/sys/sys/stat.h	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/sys/stat.h	Fri Jan 23 21:07:08 2015	(r277610)
@@ -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

Modified: head/sys/sys/syscallsubr.h
==============================================================================
--- head/sys/sys/syscallsubr.h	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/sys/sys/syscallsubr.h	Fri Jan 23 21:07:08 2015	(r277610)
@@ -99,6 +99,8 @@ int	kern_fstatfs(struct thread *td, int 
 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
 	    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,

Modified: head/usr.bin/kdump/kdump.c
==============================================================================
--- head/usr.bin/kdump/kdump.c	Fri Jan 23 21:04:59 2015	(r277609)
+++ head/usr.bin/kdump/kdump.c	Fri Jan 23 21:07:08 2015	(r277610)
@@ -714,6 +714,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_in
 			case SYS_readlinkat:
 			case SYS_renameat:
 			case SYS_unlinkat:
+			case SYS_utimensat:
 				putchar('(');
 				atfdname(*ip, decimal);
 				c = ',';



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