#define GETPROCNR 104 /* to PM */
#define ISSETUGID 106 /* to PM: ask if process is tainted */
#define GETEPINFO_O 107 /* to PM: get pid/uid/gid of an endpoint */
+#define UTIMENS 108 /* to FS: [f]utimens(); also [fl]utimes */
#define SRV_KILL 111 /* to PM: special kill call for RS */
#define GCOV_FLUSH 112 /* flush gcov data from server to gcov files */
-# $NetBSD: Makefile.inc,v 1.184 2012/04/12 22:08:32 christos Exp $
+# $NetBSD: Makefile.inc,v 1.185 2012/11/03 19:39:21 christos Exp $
# from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
# gen sources
sigset.c sigsetops.c sleep.c \
stringlist.c sysconf.c \
syslog.c telldir.c time.c \
- times.c toascii.c tolower_.c ttyname.c ttyslot.c \
- toupper_.c ualarm.c ulimit.c uname.c unvis.c usleep.c utime.c utmp.c \
+ times.c toascii.c tolower_.c ttyname.c ttyslot.c toupper_.c ualarm.c \
+ ulimit.c uname.c unvis.c usleep.c utime.c utimens.c utmp.c \
utmpx.c valloc.c vis.c wait.c waitpid.c warn.c warnx.c \
vwarn.c vwarnx.c verr.c verrx.c wordexp.c
.endif
--- /dev/null
+/* $NetBSD: utimens.c,v 1.1 2012/11/03 19:39:21 christos Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: utimens.c,v 1.1 2012/11/03 19:39:21 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#define _INCOMPLETE_XOPEN_C063
+#include <fcntl.h>
+#include <sys/stat.h>
+
+int
+utimens(const char *path, const struct timespec *times)
+{
+ return utimensat(AT_FDCWD, path, times, 0);
+}
+
+int
+lutimens(const char *path, const struct timespec *times)
+{
+ return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
+}
timer_gettime
timer_settime
undelete
-utimes
-lutimes
-futimes
utrace
uuidgen
vadvise
vectorio.c shutdown.c sigaction.c sigpending.c sigreturn.c sigsuspend.c\
sigprocmask.c socket.c socketpair.c stat.c statvfs.c symlink.c \
sync.c syscall.c sysuname.c truncate.c umask.c unlink.c write.c \
+ utimensat.c utimes.c futimes.c lutimes.c futimens.c \
_exit.c _ucontext.c environ.c __getcwd.c vfork.c sizeup.c init.c
# Minix specific syscalls.
--- /dev/null
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <sys/stat.h>
+
+int futimens(int fd, const struct timespec tv[2])
+{
+ message m;
+ static const struct timespec now[2] = { {0, UTIME_NOW}, {0, UTIME_NOW} };
+
+ if (tv == NULL) tv = now;
+
+ m.m2_i1 = fd;
+ m.m2_l1 = tv[0].tv_sec;
+ m.m2_l2 = tv[1].tv_sec;
+ m.m2_i2 = tv[0].tv_nsec;
+ m.m2_i3 = tv[1].tv_nsec;
+ m.m2_p1 = NULL;
+ m.m2_s1 = 0;
+
+ return(_syscall(VFS_PROC_NR, UTIMENS, &m));
+}
--- /dev/null
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef __weak_alias
+__weak_alias(futimes, __futimes50)
+#endif
+
+int futimes(int fd, const struct timeval tv[2])
+{
+ message m;
+
+ m.m2_i1 = fd;
+ if (tv == NULL) {
+ m.m2_l1 = m.m2_l2 = 0;
+ m.m2_i2 = m.m2_i3 = UTIME_NOW;
+ }
+ else {
+ m.m2_l1 = tv[0].tv_sec;
+ m.m2_l2 = tv[1].tv_sec;
+ m.m2_i2 = tv[0].tv_usec * 1000;
+ m.m2_i3 = tv[1].tv_usec * 1000;
+ }
+ m.m2_p1 = NULL;
+ m.m2_s1 = 0;
+
+ return(_syscall(VFS_PROC_NR, UTIMENS, &m));
+}
--- /dev/null
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __weak_alias
+__weak_alias(lutimes, __lutimes50)
+#endif
+
+int lutimes(const char *name, const struct timeval tv[2])
+{
+ message m;
+
+ if (name == NULL) return EINVAL;
+ if (name[0] == '\0') return ENOENT; /* X/Open requirement */
+ m.m2_i1 = strlen(name) + 1;
+ m.m2_p1 = (char *) __UNCONST(name);
+ if (tv == NULL) {
+ m.m2_l1 = m.m2_l2 = 0;
+ m.m2_i2 = m.m2_i3 = UTIME_NOW;
+ }
+ else {
+ m.m2_l1 = tv[0].tv_sec;
+ m.m2_l2 = tv[1].tv_sec;
+ m.m2_i2 = tv[0].tv_usec * 1000;
+ m.m2_i3 = tv[1].tv_usec * 1000;
+ }
+ m.m2_s1 = AT_SYMLINK_NOFOLLOW;
+
+ return(_syscall(VFS_PROC_NR, UTIMENS, &m));
+}
--- /dev/null
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+/* Implement a very large but not complete subset of the utimensat()
+ * Posix:2008/XOpen-7 function.
+ * Are handled the following cases:
+ * . utimensat(AT_FDCWD, "/some/absolute/path", , )
+ * . utimensat(AT_FDCWD, "some/path", , )
+ * . utimensat(fd, "/some/absolute/path", , ) although fd is useless here
+ * Are not handled the following cases:
+ * . utimensat(fd, "some/path", , ) path to a file relative to some open fd
+ */
+int utimensat(int fd, const char *name, const struct timespec tv[2],
+ int flags)
+{
+ message m;
+ static const struct timespec now[2] = { {0, UTIME_NOW}, {0, UTIME_NOW} };
+
+ if (tv == NULL) tv = now;
+
+ if (name == NULL) return EINVAL;
+ if (name[0] == '\0') return ENOENT; /* POSIX requirement */
+ if (fd != AT_FDCWD && name[0] != '/') return EINVAL; /* Not supported */
+ m.m2_i1 = strlen(name) + 1;
+ m.m2_p1 = (char *) __UNCONST(name);
+ m.m2_l1 = tv[0].tv_sec;
+ m.m2_l2 = tv[1].tv_sec;
+ m.m2_i2 = tv[0].tv_nsec;
+ m.m2_i3 = tv[1].tv_nsec;
+ if ((unsigned)flags > SHRT_MAX)
+ return EINVAL;
+ else
+ m.m2_s1 = flags;
+
+ return(_syscall(VFS_PROC_NR, UTIMENS, &m));
+}
--- /dev/null
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __weak_alias
+__weak_alias(utimes, __utimes50)
+#endif
+
+int utimes(const char *name, const struct timeval tv[2])
+{
+ message m;
+
+ if (name == NULL) return EINVAL;
+ if (name[0] == '\0') return ENOENT; /* X/Open requirement */
+ m.m2_i1 = strlen(name) + 1;
+ m.m2_p1 = (char *) __UNCONST(name);
+ if (tv == NULL) {
+ m.m2_l1 = m.m2_l2 = 0;
+ m.m2_i2 = m.m2_i3 = UTIME_NOW;
+ }
+ else {
+ m.m2_l1 = tv[0].tv_sec;
+ m.m2_l2 = tv[1].tv_sec;
+ m.m2_i2 = tv[0].tv_usec * 1000;
+ m.m2_i3 = tv[1].tv_usec * 1000;
+ }
+ m.m2_s1 = 0;
+
+ return(_syscall(VFS_PROC_NR, UTIMENS, &m));
+}
no_sys, /* 105 = unused */
do_get, /* 106 = issetugid */
do_getepinfo_o, /* 107 = getepinfo XXX: old implementation*/
- no_sys, /* 108 = unused */
+ no_sys, /* 108 = (utimens) */
no_sys, /* 109 = unused */
no_sys, /* 110 = unused */
do_srv_kill, /* 111 = srv_kill */
#define utime_file m2_p1
#define utime_length m2_i1
#define utime_strlen m2_i2
+#define utimens_fd m2_i1
+#define utimens_ansec m2_i2
+#define utimens_mnsec m2_i3
+#define utimens_flags m2_s1
#define whence m2_i2
#define svrctl_req m2_i1
#define svrctl_argp m2_p1
/* time.c */
int do_utime(void);
+int do_utimens(void);
/* tll.c */
void tll_downgrade(tll_t *tllp);
no_sys, /* 105 = unused */
no_sys, /* 106 = unused */
no_sys, /* 107 = (getepinfo) */
- no_sys, /* 108 = unused */
+ do_utimens, /* 108 = utimens */
no_sys, /* 109 = unused */
no_sys, /* 110 = unused */
no_sys, /* 111 = (srv_kill) */
*
* The entry points into this file are
* do_utime: perform the UTIME system call
+ * do_utimens: perform the UTIMENS system call
*/
#include "fs.h"
#include <minix/callnr.h>
#include <minix/com.h>
#include <time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include "file.h"
#include "fproc.h"
#include "path.h"
#include <minix/vfsif.h>
#include "vmnt.h"
+#define UTIMENS_STYLE 0 /* utimes(2)/utimensat(2) style, named file */
+#define FUTIMENS_STYLE 1 /* futimens(2)/futimes(2) style, file desc. */
+
/*===========================================================================*
* do_utime *
*===========================================================================*/
-int do_utime()
+int do_utime(void)
{
/* Perform the utime(name, timep) system call. */
int r;
put_vnode(vp);
return(r);
}
+
+
+/*===========================================================================*
+ * do_utimens *
+ *===========================================================================*/
+int do_utimens(void)
+{
+/* Perform the utimens(name, times, flag) system call, and its friends.
+ * Implement a very large but not complete subset of the utimensat()
+ * Posix:2008/XOpen-7 function.
+ * Are handled all the following cases:
+ * . utimensat(AT_FDCWD, "/some/absolute/path", , )
+ * . utimensat(AT_FDCWD, "some/path", , )
+ * . utimens("anything", ) really special case of the above two
+ * . lutimens("anything", ) also really special case of the above
+ * . utimensat(fd, "/some/absolute/path", , ) although fd is useless here
+ * . futimens(fd, )
+ * Are not handled the following cases:
+ * . utimensat(fd, "some/path", , ) path to a file relative to some open fd
+ */
+ int r, kind, lookup_flags;
+ struct vnode *vp;
+ struct filp *filp = NULL; /* initialization required by clueless GCC */
+ struct vmnt *vmp;
+ struct timespec actim, modtim, now, newactim, newmodtim;
+ char fullpath[PATH_MAX];
+ struct lookup resolve;
+ vir_bytes vname;
+ size_t vname_length;
+
+ /* The case times==NULL is handled by the caller, replaced with UTIME_NOW */
+ actim.tv_sec = job_m_in.utime_actime;
+ actim.tv_nsec = job_m_in.utimens_ansec;
+ modtim.tv_sec = job_m_in.utime_modtime;
+ modtim.tv_nsec = job_m_in.utimens_mnsec;
+
+ if (job_m_in.utime_file != NULL) {
+ kind = UTIMENS_STYLE;
+ if (job_m_in.utimens_flags & ~AT_SYMLINK_NOFOLLOW)
+ return EINVAL; /* unknown flag */
+ /* Temporarily open the file */
+ vname = (vir_bytes) job_m_in.utime_file;
+ vname_length = (size_t) job_m_in.utime_length;
+ if (job_m_in.utimens_flags & AT_SYMLINK_NOFOLLOW)
+ lookup_flags = PATH_RET_SYMLINK;
+ else
+ lookup_flags = PATH_NOFLAGS;
+ lookup_init(&resolve, fullpath, lookup_flags, &vmp, &vp);
+ resolve.l_vmnt_lock = VMNT_READ;
+ resolve.l_vnode_lock = VNODE_READ;
+ /* Temporarily open the file */
+ if (fetch_name(vname, vname_length, fullpath) != OK) return(err_code);
+ if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code);
+ }
+ else {
+ kind = FUTIMENS_STYLE;
+ /* Change timestamps on already-opened fd. Is it valid? */
+ if (job_m_in.utimens_flags != 0)
+ return EINVAL; /* unknown flag */
+ if ((filp = get_filp(job_m_in.utimens_fd, VNODE_READ)) == NULL)
+ return err_code;
+ vp = filp->filp_vno;
+ }
+
+ r = OK;
+ /* Only the owner of a file or the super user can change timestamps. */
+ if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM;
+ /* Need write permission (or super user) to 'touch' the file */
+ if (r != OK && actim.tv_nsec == UTIME_NOW
+ && modtim.tv_nsec == UTIME_NOW) r = forbidden(fp, vp, W_BIT);
+ if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */
+
+ if (r == OK) {
+ /* Do we need to ask for current time? */
+ if (actim.tv_nsec == UTIME_NOW
+ || actim.tv_nsec == UTIME_OMIT
+ || modtim.tv_nsec == UTIME_NOW
+ || modtim.tv_nsec == UTIME_OMIT) {
+ now = clock_timespec();
+ }
+
+ /* Build the request */
+ switch (actim.tv_nsec) {
+ case UTIME_NOW:
+ newactim = now;
+ break;
+ case UTIME_OMIT:
+ newactim.tv_nsec = UTIME_OMIT;
+ /* Be nice with old FS, put a sensible value in
+ * otherwise not used field for seconds
+ */
+ newactim.tv_sec = now.tv_sec;
+ break;
+ default:
+ if ( (unsigned)actim.tv_nsec >= 1000000000)
+ r = EINVAL;
+ else
+ newactim = actim;
+ break;
+ }
+ switch (modtim.tv_nsec) {
+ case UTIME_NOW:
+ newmodtim = now;
+ break;
+ case UTIME_OMIT:
+ newmodtim.tv_nsec = UTIME_OMIT;
+ /* Be nice with old FS, put a sensible value */
+ newmodtim.tv_sec = now.tv_sec;
+ break;
+ default:
+ if ( (unsigned)modtim.tv_nsec >= 1000000000)
+ r = EINVAL;
+ else
+ newmodtim = modtim;
+ break;
+ }
+ }
+
+ if (r == OK)
+ /* Issue request */
+ r = req_utime(vp->v_fs_e, vp->v_inode_nr, &newactim, &newmodtim);
+
+ if (kind == UTIMENS_STYLE) {
+ /* Close the temporary */
+ unlock_vnode(vp);
+ unlock_vmnt(vmp);
+ put_vnode(vp);
+ }
+ else { /* Change timestamps on opened fd. */
+ unlock_filp(filp);
+ }
+ return r;
+}
/*
* Constants for X/Open Extended API set 2 (a.k.a. C063)
+ * linkat(2) - also part of Posix-2008/XPG7
*/
-#if defined(_INCOMPLETE_XOPEN_C063) || defined(_KERNEL)
+#if (_POSIX_C_SOURCE - 0) >= 200809L || (_XOPEN_SOURCE - 0) >= 700 || \
+ defined(_NETBSD_SOURCE)
+#if defined(_INCOMPLETE_XOPEN_C063) || defined(_KERNEL) || defined(__minix)
#define AT_FDCWD -100 /* Use cwd for relative link target */
-#define AT_EACCESS 0x100 /* Use euig/egid for access checks */
+#define AT_EACCESS 0x100 /* Use euid/egid for access checks */
#define AT_SYMLINK_NOFOLLOW 0x200 /* Do not follow symlinks */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symlinks */
#define AT_REMOVEDIR 0x800 /* Remove directory only */
#endif
+#endif
#ifndef _KERNEL
int lchmod(const char *, mode_t);
#endif /* defined(_NETBSD_SOURCE) && !defined(__minix) */
-#ifndef __minix
#ifndef __LIBC12_SOURCE__
/*
* X/Open Extended API set 2 (a.k.a. C063)
int futimens(int, const struct timespec *);
#endif
#endif
-#endif /* !__minix */
__END_DECLS
int setitimer(int, const struct itimerval * __restrict,
struct itimerval * __restrict) __RENAME(__setitimer50);
#endif /* _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE || _NETBSD_SOURCE */
+#if defined(_XOPEN_SOURCE) || defined(_NETBSD_SOURCE)
+int utimes(const char *, const struct timeval [2]) __RENAME(__utimes50);
+#endif /* _XOPEN_SOURCE || _NETBSD_SOURCE */
#if defined(_NETBSD_SOURCE) || defined(HAVE_NBTOOL_CONFIG_H)
int adjtime(const struct timeval *, struct timeval *) __RENAME(__adjtime50);
-#ifndef __minix
int futimes(int, const struct timeval [2]) __RENAME(__futimes50);
int lutimes(const char *, const struct timeval [2]) __RENAME(__lutimes50);
-#endif /* !__minix */
int settimeofday(const struct timeval * __restrict,
const void *__restrict) __RENAME(__settimeofday50);
#endif /* _NETBSD_SOURCE */
#endif
static int
-utimes(const char *path, const struct timeval times[2])
+fake_utimes(const char *path, const struct timeval times[2])
{
return -1;
}
+#undef utimes
+#define utimes(path, times) fake_utimes(path, times)
#endif
int