summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2011-07-07 23:45:01 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2011-07-07 23:45:01 +0000
commita6f6d4ae7f4c39fb7c43f0efb6e2ba80805bc886 (patch)
treef1ceb953aa46a8915d2ddf6404f7846f3a9dfbce /sys
parentf13884981a67ed7d87352c2dd4950c71bb16a7f4 (diff)
Add new syscall entries to support the openat(2) family of functions
added in POSIX Issue 7: openat(), mknodat(), mkfifoat(), linkat(), symlinkat(), unlinkat(), faccessat(), fstatat(), readlinkat(), fchmodat(), fchownat(), utimensat(), renameat(), and mkdirat(). This diff mostly just refactors the existing sys_foo() logic into a common dofooat() function that can then be called by both sys_foo() and sys_fooat(). Some of the new system calls support new flags to control their behavior, and proper support for these will be added in subsequent diffs. Incorporating suggestions from thib@, guenther@, and tedu@. ok tedu@, thib@, deraadt@, guenther@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/diskmap.c3
-rw-r--r--sys/kern/exec_script.c3
-rw-r--r--sys/kern/syscalls.master30
-rw-r--r--sys/kern/vfs_lookup.c14
-rw-r--r--sys/kern/vfs_syscalls.c489
-rw-r--r--sys/sys/fcntl.h5
-rw-r--r--sys/sys/namei.h11
7 files changed, 494 insertions, 61 deletions
diff --git a/sys/dev/diskmap.c b/sys/dev/diskmap.c
index 62da4c2de3d..c2197d8abd7 100644
--- a/sys/dev/diskmap.c
+++ b/sys/dev/diskmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diskmap.c,v 1.5 2011/07/02 16:53:17 jsing Exp $ */
+/* $OpenBSD: diskmap.c,v 1.6 2011/07/07 23:45:00 matthew Exp $ */
/*
* Copyright (c) 2009, 2010 Joel Sing <jsing@openbsd.org>
@@ -85,6 +85,7 @@ diskmapioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
goto bad;
ndp.ni_segflg = UIO_SYSSPACE;
+ ndp.ni_dirfd = AT_FDCWD;
ndp.ni_dirp = devname;
ndp.ni_cnd.cn_proc = p;
if ((error = vn_open(&ndp, fp->f_flag, 0)) != 0)
diff --git a/sys/kern/exec_script.c b/sys/kern/exec_script.c
index b48dd20f337..dc1cc381b84 100644
--- a/sys/kern/exec_script.c
+++ b/sys/kern/exec_script.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_script.c,v 1.25 2007/10/29 14:12:19 chl Exp $ */
+/* $OpenBSD: exec_script.c,v 1.26 2011/07/07 23:45:00 matthew Exp $ */
/* $NetBSD: exec_script.c,v 1.13 1996/02/04 02:15:06 christos Exp $ */
/*
@@ -200,6 +200,7 @@ check_shell:
#endif
/* set up the parameters for the recursive check_exec() call */
+ epp->ep_ndp->ni_dirfd = AT_FDCWD;
epp->ep_ndp->ni_dirp = shellname;
epp->ep_ndp->ni_segflg = UIO_SYSSPACE;
epp->ep_flags |= EXEC_INDIR;
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 3594ce6c090..9c8ace8dab3 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.110 2011/07/07 18:30:50 tedu Exp $
+; $OpenBSD: syscalls.master,v 1.111 2011/07/07 23:45:00 matthew Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -565,3 +565,31 @@
311 STD { int sys_getrtable(void); }
312 STD { int sys_getdirentries(int fd, char *buf, \
int count, off_t *basep); }
+313 STD { int sys_faccessat(int fd, const char *path, \
+ int amode, int flag); }
+314 STD { int sys_fchmodat(int fd, const char *path, \
+ mode_t mode, int flag); }
+315 STD { int sys_fchownat(int fd, const char *path, \
+ uid_t uid, gid_t gid, int flag); }
+316 STD { int sys_fstatat(int fd, const char *path, \
+ struct stat *buf, int flag); }
+317 STD { int sys_linkat(int fd1, const char *path1, int fd2, \
+ const char *path2, int flag); }
+318 STD { int sys_mkdirat(int fd, const char *path, \
+ mode_t mode); }
+319 STD { int sys_mkfifoat(int fd, const char *path, \
+ mode_t mode); }
+320 STD { int sys_mknodat(int fd, const char *path, \
+ mode_t mode, dev_t dev); }
+321 STD { int sys_openat(int fd, const char *path, int flags, \
+ ... mode_t mode); }
+322 STD { ssize_t sys_readlinkat(int fd, const char *path, \
+ char *buf, size_t count); }
+323 STD { int sys_renameat(int fromfd, const char *from, \
+ int tofd, const char *to); }
+324 STD { int sys_symlinkat(const char *path, int fd, \
+ const char *link); }
+325 STD { int sys_unlinkat(int fd, const char *path, \
+ int flag); }
+326 STD { int sys_utimensat(int fd, const char *path, \
+ const struct timespec *times, int flag); }
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index db7ab3bc7d9..d860dee4fd5 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_lookup.c,v 1.43 2010/09/09 10:37:03 thib Exp $ */
+/* $OpenBSD: vfs_lookup.c,v 1.44 2011/07/07 23:45:00 matthew Exp $ */
/* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */
/*
@@ -50,6 +50,8 @@
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <sys/hash.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
#ifdef KTRACE
#include <sys/ktrace.h>
@@ -167,9 +169,17 @@ namei(struct nameidata *ndp)
if (cnp->cn_pnbuf[0] == '/') {
dp = ndp->ni_rootdir;
vref(dp);
- } else {
+ } else if (ndp->ni_dirfd == AT_FDCWD) {
dp = fdp->fd_cdir;
vref(dp);
+ } else {
+ struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
+ if (fp == NULL || fp->f_type != DTYPE_VNODE)
+ return (EBADF);
+ dp = (struct vnode *)fp->f_data;
+ if (dp->v_type != VDIR)
+ return (EBADF);
+ vref(dp);
}
for (;;) {
if (!dp->v_mount) {
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index d441dc1c654..8747e4b5e6e 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_syscalls.c,v 1.168 2011/07/06 04:49:13 guenther Exp $ */
+/* $OpenBSD: vfs_syscalls.c,v 1.169 2011/07/07 23:45:00 matthew Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
/*
@@ -71,6 +71,27 @@ int copyout_statfs(struct statfs *, void *, struct proc *);
int getdirentries_internal(struct proc *, int, char *, int, off_t *,
register_t *);
+int doopenat(struct proc *, int, const char *, int, mode_t, register_t *);
+int domknodat(struct proc *, int, const char *, mode_t, dev_t, register_t *);
+int domkfifoat(struct proc *, int, const char *, mode_t, register_t *);
+int dolinkat(struct proc *, int, const char *, int, const char *, int,
+ register_t *);
+int dosymlinkat(struct proc *, const char *, int, const char *, register_t *);
+int dounlinkat(struct proc *, int, const char *, int, register_t *);
+int dofaccessat(struct proc *, int, const char *, int, int, register_t *);
+int dofstatat(struct proc *, int, const char *, struct stat *, int,
+ register_t *);
+int doreadlinkat(struct proc *, int, const char *, char *, size_t,
+ register_t *);
+int dofchmodat(struct proc *, int, const char *, mode_t, int, register_t *);
+int dofchownat(struct proc *, int, const char *, uid_t, gid_t, int,
+ register_t *);
+int dorenameat(struct proc *, int, const char *, int, const char *,
+ register_t *);
+int domkdirat(struct proc *, int, const char *, mode_t, register_t *);
+int doutimensat(struct proc *, int, const char *, const struct timeval *,
+ int, register_t *);
+
/*
* Virtual File System System Calls
*/
@@ -797,6 +818,29 @@ sys_open(struct proc *p, void *v, register_t *retval)
syscallarg(int) flags;
syscallarg(mode_t) mode;
} */ *uap = v;
+
+ return (doopenat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, flags),
+ SCARG(uap, mode), retval));
+}
+
+int
+sys_openat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_openat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(int) flags;
+ syscallarg(mode_t) mode;
+ } */ *uap = v;
+
+ return (doopenat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, flags), SCARG(uap, mode), retval));
+}
+
+int
+doopenat(struct proc *p, int fd, const char *path, int oflags, mode_t mode,
+ register_t *retval)
+{
struct filedesc *fdp = p->p_fd;
struct file *fp;
struct vnode *vp;
@@ -811,9 +855,9 @@ sys_open(struct proc *p, void *v, register_t *retval)
if ((error = falloc(p, &fp, &indx)) != 0)
goto out;
- flags = FFLAGS(SCARG(uap, flags));
- cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ flags = FFLAGS(oflags);
+ cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
+ NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
p->p_dupfd = -1; /* XXX check for fdopen */
if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) {
localtrunc = 1;
@@ -1139,6 +1183,29 @@ sys_mknod(struct proc *p, void *v, register_t *retval)
syscallarg(mode_t) mode;
syscallarg(int) dev;
} */ *uap = v;
+
+ return (domknodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
+ SCARG(uap, dev), retval));
+}
+
+int
+sys_mknodat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_mknodat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(mode_t) mode;
+ syscallarg(dev_t) dev;
+ } */ *uap = v;
+
+ return (domknodat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, mode), SCARG(uap, dev), retval));
+}
+
+int
+domknodat(struct proc *p, int fd, const char *path, mode_t mode, dev_t dev,
+ register_t *retval)
+{
struct vnode *vp;
struct vattr vattr;
int error;
@@ -1148,7 +1215,7 @@ sys_mknod(struct proc *p, void *v, register_t *retval)
return (error);
if (p->p_fd->fd_rdir)
return (EINVAL);
- NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
+ NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -1156,10 +1223,10 @@ sys_mknod(struct proc *p, void *v, register_t *retval)
error = EEXIST;
else {
VATTR_NULL(&vattr);
- vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
- vattr.va_rdev = SCARG(uap, dev);
+ vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
+ vattr.va_rdev = dev;
- switch (SCARG(uap, mode) & S_IFMT) {
+ switch (mode & S_IFMT) {
case S_IFMT: /* used by badsect to flag bad sectors */
vattr.va_type = VBAD;
break;
@@ -1195,18 +1262,39 @@ sys_mknod(struct proc *p, void *v, register_t *retval)
int
sys_mkfifo(struct proc *p, void *v, register_t *retval)
{
-#ifndef FIFO
- return (EOPNOTSUPP);
-#else
struct sys_mkfifo_args /* {
syscallarg(const char *) path;
syscallarg(mode_t) mode;
} */ *uap = v;
+
+ return (domkfifoat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
+ retval));
+}
+
+int
+sys_mkfifoat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_mkfifoat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(mode_t) mode;
+ } */ *uap = v;
+
+ return (domkfifoat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, mode), retval));
+}
+
+int
+domkfifoat(struct proc *p, int fd, const char *path, mode_t mode, register_t *retval)
+{
+#ifndef FIFO
+ return (EOPNOTSUPP);
+#else
struct vattr vattr;
int error;
struct nameidata nd;
- NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
+ NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
if (nd.ni_vp != NULL) {
@@ -1220,7 +1308,7 @@ sys_mkfifo(struct proc *p, void *v, register_t *retval)
}
VATTR_NULL(&vattr);
vattr.va_type = VFIFO;
- vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
+ vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
#endif /* FIFO */
}
@@ -1236,12 +1324,40 @@ sys_link(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(const char *) link;
} */ *uap = v;
+
+ return (dolinkat(p, AT_FDCWD, SCARG(uap, path), AT_FDCWD,
+ SCARG(uap, link), 0, retval));
+}
+
+int
+sys_linkat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_linkat_args /* {
+ syscallarg(int) fd1;
+ syscallarg(const char *) path1;
+ syscallarg(int) fd2;
+ syscallarg(const char *) path2;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ return (dolinkat(p, SCARG(uap, fd1), SCARG(uap, path1),
+ SCARG(uap, fd2), SCARG(uap, path2), SCARG(uap, flag), retval));
+}
+
+int
+dolinkat(struct proc *p, int fd1, const char *path1, int fd2,
+ const char *path2, int flag, register_t *retval)
+{
struct vnode *vp;
struct nameidata nd;
int error;
int flags;
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ /* XXX: Support AT_SYMLINK_FOLLOW. */
+ if (flag != 0)
+ return (ENOTSUP);
+
+ NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd1, path1, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -1251,7 +1367,7 @@ sys_link(struct proc *p, void *v, register_t *retval)
flags |= STRIPSLASHES;
}
- NDINIT(&nd, CREATE, flags, UIO_USERSPACE, SCARG(uap, link), p);
+ NDINITAT(&nd, CREATE, flags, UIO_USERSPACE, fd2, path2, p);
if ((error = namei(&nd)) != 0)
goto out;
if (nd.ni_vp) {
@@ -1281,16 +1397,38 @@ sys_symlink(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(const char *) link;
} */ *uap = v;
+
+ return (dosymlinkat(p, SCARG(uap, path), AT_FDCWD, SCARG(uap, link),
+ retval));
+}
+
+int
+sys_symlinkat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_symlinkat_args /* {
+ syscallarg(const char *) path;
+ syscallarg(int) fd;
+ syscallarg(const char *) link;
+ } */ *uap = v;
+
+ return (dosymlinkat(p, SCARG(uap, path), SCARG(uap, fd),
+ SCARG(uap, link), retval));
+}
+
+int
+dosymlinkat(struct proc *p, const char *upath, int fd, const char *link,
+ register_t *retval)
+{
struct vattr vattr;
char *path;
int error;
struct nameidata nd;
path = pool_get(&namei_pool, PR_WAITOK);
- error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
+ error = copyinstr(upath, path, MAXPATHLEN, NULL);
if (error)
goto out;
- NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
+ NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, link, p);
if ((error = namei(&nd)) != 0)
goto out;
if (nd.ni_vp) {
@@ -1321,12 +1459,37 @@ sys_unlink(struct proc *p, void *v, register_t *retval)
struct sys_unlink_args /* {
syscallarg(const char *) path;
} */ *uap = v;
+
+ return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), 0, retval));
+}
+
+int
+sys_unlinkat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_unlinkat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ return (dounlinkat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, flag), retval));
+}
+
+int
+dounlinkat(struct proc *p, int fd, const char *path, int flag,
+ register_t *retval)
+{
struct vnode *vp;
int error;
struct nameidata nd;
- NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+ /* XXX: Support AT_REMOVEDIR. */
+ if (flag != 0)
+ return (ENOTSUP);
+
+ NDINITAT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
+ fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -1427,32 +1590,56 @@ sys_access(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(int) flags;
} */ *uap = v;
+
+ return (dofaccessat(p, AT_FDCWD, SCARG(uap, path),
+ SCARG(uap, flags), 0, retval));
+}
+
+int
+sys_faccessat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_faccessat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(int) amode;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ return (dofaccessat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, amode), SCARG(uap, flag), retval));
+}
+
+int
+dofaccessat(struct proc *p, int fd, const char *path, int amode, int flag,
+ register_t *retval)
+{
struct ucred *cred = p->p_ucred;
struct vnode *vp;
int error, flags, t_gid, t_uid;
struct nameidata nd;
- int userflags = SCARG(uap, flags);
- if (userflags & ~(R_OK | W_OK | X_OK))
+ if (amode & ~(R_OK | W_OK | X_OK))
return (EINVAL);
+ /* XXX: Support AT_EACCESS. */
+ if (flag != 0)
+ return (ENOTSUP);
t_uid = cred->cr_uid;
t_gid = cred->cr_gid;
cred->cr_uid = p->p_cred->p_ruid;
cred->cr_gid = p->p_cred->p_rgid;
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+ NDINITAT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
goto out1;
vp = nd.ni_vp;
/* Flags == 0 means only check for existence. */
- if (userflags) {
+ if (amode) {
flags = 0;
- if (userflags & R_OK)
+ if (amode & R_OK)
flags |= VREAD;
- if (userflags & W_OK)
+ if (amode & W_OK)
flags |= VWRITE;
- if (userflags & X_OK)
+ if (amode & X_OK)
flags |= VEXEC;
error = VOP_ACCESS(vp, flags, cred, p);
@@ -1477,12 +1664,38 @@ sys_stat(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(struct stat *) ub;
} */ *uap = v;
+
+ return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub), 0,
+ retval));
+}
+
+int
+sys_fstatat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_fstatat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(struct stat *) buf;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ return (dofstatat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, buf), SCARG(uap, flag), retval));
+}
+
+int
+dofstatat(struct proc *p, int fd, const char *path, struct stat *buf,
+ int flag, register_t *retval)
+{
struct stat sb;
int error;
struct nameidata nd;
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+ /* XXX: Support AT_SYMLINK_NOFOLLOW (and make lstat use this??) */
+ if (flag != 0)
+ return (ENOTSUP);
+
+ NDINITAT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
error = vn_stat(nd.ni_vp, &sb, p);
@@ -1492,7 +1705,7 @@ sys_stat(struct proc *p, void *v, register_t *retval)
/* Don't let non-root see generation numbers (for NFS security) */
if (suser(p, 0))
sb.st_gen = 0;
- error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
+ error = copyout(&sb, buf, sizeof(sb));
return (error);
}
@@ -1561,22 +1774,43 @@ sys_readlink(struct proc *p, void *v, register_t *retval)
syscallarg(char *) buf;
syscallarg(size_t) count;
} */ *uap = v;
+
+ return (doreadlinkat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, buf),
+ SCARG(uap, count), retval));
+}
+
+int
+sys_readlinkat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_readlinkat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(char *) buf;
+ syscallarg(size_t) count;
+ } */ *uap = v;
+
+ return (doreadlinkat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, buf), SCARG(uap, count), retval));
+}
+
+int
+doreadlinkat(struct proc *p, int fd, const char *path, char *buf,
+ size_t count, register_t *retval)
+{
struct vnode *vp;
struct iovec aiov;
struct uio auio;
int error;
struct nameidata nd;
- size_t count = SCARG(uap, count);
- NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+ NDINITAT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
if (vp->v_type != VLNK)
error = EINVAL;
else {
- aiov.iov_base = SCARG(uap, buf);
+ aiov.iov_base = buf;
aiov.iov_len = count;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
@@ -1692,15 +1926,41 @@ sys_chmod(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(mode_t) mode;
} */ *uap = v;
+
+ return (dofchmodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
+ 0, retval));
+}
+
+int
+sys_fchmodat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_fchmodat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(mode_t) mode;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ return (dofchmodat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, mode), SCARG(uap, flag), retval));
+}
+
+int
+dofchmodat(struct proc *p, int fd, const char *path, mode_t mode, int flag,
+ register_t *retval)
+{
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
- if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
+ if (mode & ~(S_IFMT | ALLPERMS))
return (EINVAL);
+ /* XXX: Support AT_SYMLINK_NOFOLLOW. */
+ if (flag != 0)
+ return (ENOTSUP);
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -1709,7 +1969,7 @@ sys_chmod(struct proc *p, void *v, register_t *retval)
error = EROFS;
else {
VATTR_NULL(&vattr);
- vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
+ vattr.va_mode = mode & ALLPERMS;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
}
vput(vp);
@@ -1763,15 +2023,41 @@ sys_chown(struct proc *p, void *v, register_t *retval)
syscallarg(uid_t) uid;
syscallarg(gid_t) gid;
} */ *uap = v;
+
+ return (dofchownat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, uid),
+ SCARG(uap, gid), 0, retval));
+}
+
+int
+sys_fchownat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_fchownat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(uid_t) uid;
+ syscallarg(gid_t) gid;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ return (dofchownat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, uid), SCARG(uap, gid), SCARG(uap, flag), retval));
+}
+
+int
+dofchownat(struct proc *p, int fd, const char *path, uid_t uid, gid_t gid,
+ int flag, register_t *retval)
+{
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
mode_t mode;
- uid_t uid = SCARG(uap, uid);
- gid_t gid = SCARG(uap, gid);
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ /* XXX: Support AT_SYMLINK_NOFOLLOW. */
+ if (flag != 0)
+ return (ENOTSUP);
+
+ NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -1911,29 +2197,82 @@ sys_utimes(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(const struct timeval *) tptr;
} */ *uap = v;
+
+ struct timeval tv[2];
+ const struct timeval *tvp;
+ int error;
+
+ tvp = SCARG(uap, tptr);
+ if (tvp != NULL) {
+ error = copyin(tvp, tv, sizeof(tv));
+ if (error)
+ return (error);
+ tvp = tv;
+ }
+
+ return (doutimensat(p, AT_FDCWD, SCARG(uap, path), tvp, 0, retval));
+}
+
+int
+sys_utimensat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_utimensat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(const struct timespec *) times;
+ syscallarg(int) flag;
+ } */ *uap = v;
+
+ struct timeval tv[2];
+ struct timespec ts[2];
+ const struct timeval *tvp = NULL;
+ const struct timespec *tsp;
+ int error;
+
+ tsp = SCARG(uap, times);
+ if (tsp != NULL) {
+ error = copyin(tsp, ts, sizeof(ts));
+ if (error)
+ return (error);
+ tv[0].tv_sec = ts[0].tv_sec;
+ tv[0].tv_usec = ts[0].tv_nsec / 1000;
+ tv[1].tv_sec = ts[1].tv_sec;
+ tv[1].tv_usec = ts[1].tv_nsec / 1000;
+ tvp = tv;
+ }
+
+ return (doutimensat(p, SCARG(uap, fd), SCARG(uap, path), tvp,
+ SCARG(uap, flag), retval));
+}
+
+int
+doutimensat(struct proc *p, int fd, const char *path,
+ const struct timeval *tvp, int flag, register_t *retval)
+{
struct vnode *vp;
struct timeval tv[2];
struct vattr vattr;
int error;
struct nameidata nd;
+ /* XXX: Support AT_SYMLINK_NOFOLLOW. */
+ if (flag != 0)
+ return (ENOTSUP);
+
VATTR_NULL(&vattr);
- if (SCARG(uap, tptr) == NULL) {
+ if (tvp == NULL) {
getmicrotime(&tv[0]);
tv[1] = tv[0];
vattr.va_vaflags |= VA_UTIMES_NULL;
} else {
- error = copyin(SCARG(uap, tptr), tv,
- sizeof(tv));
- if (error)
- return (error);
+ bcopy(tvp, tv, sizeof(tv));
/* XXX workaround timeval matching the VFS constant VNOVAL */
if (tv[0].tv_sec == VNOVAL)
tv[0].tv_sec = VNOVAL - 1;
if (tv[1].tv_sec == VNOVAL)
tv[1].tv_sec = VNOVAL - 1;
}
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -2117,13 +2456,36 @@ sys_rename(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) from;
syscallarg(const char *) to;
} */ *uap = v;
+
+ return (dorenameat(p, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
+ SCARG(uap, to), retval));
+}
+
+int
+sys_renameat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_renameat_args /* {
+ syscallarg(int) fromfd;
+ syscallarg(const char *) from;
+ syscallarg(int) tofd;
+ syscallarg(const char *) to;
+ } */ *uap = v;
+
+ return (dorenameat(p, SCARG(uap, fromfd), SCARG(uap, from),
+ SCARG(uap, tofd), SCARG(uap, to), retval));
+}
+
+int
+dorenameat(struct proc *p, int fromfd, const char *from, int tofd,
+ const char *to, register_t *retval)
+{
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
int error;
int flags;
- NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
- SCARG(uap, from), p);
+ NDINITAT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
+ fromfd, from, p);
if ((error = namei(&fromnd)) != 0)
return (error);
fvp = fromnd.ni_vp;
@@ -2135,8 +2497,7 @@ sys_rename(struct proc *p, void *v, register_t *retval)
if (fvp->v_type == VDIR)
flags |= STRIPSLASHES;
- NDINIT(&tond, RENAME, flags,
- UIO_USERSPACE, SCARG(uap, to), p);
+ NDINITAT(&tond, RENAME, flags, UIO_USERSPACE, tofd, to, p);
if ((error = namei(&tond)) != 0) {
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
vrele(fromnd.ni_dvp);
@@ -2203,13 +2564,35 @@ sys_mkdir(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
syscallarg(mode_t) mode;
} */ *uap = v;
+
+ return (domkdirat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
+ retval));
+}
+
+int
+sys_mkdirat(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_mkdirat_args /* {
+ syscallarg(int) fd;
+ syscallarg(const char *) path;
+ syscallarg(mode_t) mode;
+ } */ *uap = v;
+
+ return (domkdirat(p, SCARG(uap, fd), SCARG(uap, path),
+ SCARG(uap, mode), retval));
+}
+
+int
+domkdirat(struct proc *p, int fd, const char *path, mode_t mode,
+ register_t *retval)
+{
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
- NDINIT(&nd, CREATE, LOCKPARENT | STRIPSLASHES,
- UIO_USERSPACE, SCARG(uap, path), p);
+ NDINITAT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, UIO_USERSPACE,
+ fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -2224,7 +2607,7 @@ sys_mkdir(struct proc *p, void *v, register_t *retval)
}
VATTR_NULL(&vattr);
vattr.va_type = VDIR;
- vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
+ vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
if (!error)
vput(nd.ni_vp);
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 7a62f43efe3..edc6743b788 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fcntl.h,v 1.12 2011/06/28 10:15:38 thib Exp $ */
+/* $OpenBSD: fcntl.h,v 1.13 2011/07/07 23:45:00 matthew Exp $ */
/* $NetBSD: fcntl.h,v 1.8 1995/03/26 20:24:12 jtc Exp $ */
/*-
@@ -188,6 +188,9 @@ struct flock {
#define LOCK_UN 0x08 /* unlock file */
#endif
+#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
+#define AT_FDCWD -100
+#endif
#ifndef _KERNEL
__BEGIN_DECLS
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index ee8c624ccd4..e7ca35636b0 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: namei.h,v 1.25 2010/09/09 10:37:04 thib Exp $ */
+/* $OpenBSD: namei.h,v 1.26 2011/07/07 23:45:00 matthew Exp $ */
/* $NetBSD: namei.h,v 1.11 1996/02/09 18:25:20 christos Exp $ */
/*
@@ -50,6 +50,7 @@ struct nameidata {
/*
* Arguments to namei/lookup.
*/
+ int ni_dirfd; /* dirfd from *at() functions */
const char *ni_dirp; /* pathname pointer */
enum uio_seg ni_segflg; /* location of pathname */
/* u_long ni_nameiop; namei operation */
@@ -144,13 +145,19 @@ struct nameidata {
/*
* Initialization of an nameidata structure.
*/
-#define NDINIT(ndp, op, flags, segflg, namep, p) { \
+#define NDINITAT(ndp, op, flags, segflg, dirfd, namep, p) { \
(ndp)->ni_cnd.cn_nameiop = op; \
(ndp)->ni_cnd.cn_flags = flags; \
(ndp)->ni_segflg = segflg; \
+ (ndp)->ni_dirfd = dirfd; \
(ndp)->ni_dirp = namep; \
(ndp)->ni_cnd.cn_proc = p; \
}
+#define NDINIT(ndp, op, flags, segflp, namep, p) \
+ NDINITAT(ndp, op, flags, segflp, AT_FDCWD, namep, p)
+
+/* Defined for users of NDINIT(). */
+#define AT_FDCWD -100
#endif
/*