Index: kern/init_sysent.c =================================================================== RCS file: /cvsroot/src/sys/kern/init_sysent.c,v retrieving revision 1.234 diff -u -p -r1.234 init_sysent.c --- kern/init_sysent.c 19 Nov 2008 18:40:03 -0000 1.234 +++ kern/init_sysent.c 3 Dec 2008 10:51:02 -0000 @@ -1,14 +1,14 @@ -/* $NetBSD: init_sysent.c,v 1.234 2008/11/19 18:40:03 ad Exp $ */ +/* $NetBSD$ */ /* * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * created from NetBSD: syscalls.master,v 1.216 2008/11/19 18:36:07 ad Exp + * created from NetBSD: syscalls.master,v 1.217 2008/11/21 07:34:46 pooka Exp */ #include -__KERNEL_RCSID(0, "$NetBSD: init_sysent.c,v 1.234 2008/11/19 18:40:03 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD$"); #include "opt_ntp.h" #include "opt_sysv.h" @@ -1016,10 +1016,10 @@ struct sysent sysent[] = { (sy_call_t *)sys__pset_bind }, /* 415 = _pset_bind */ { ns(struct sys___posix_fadvise50_args), 0, (sy_call_t *)sys___posix_fadvise50 },/* 416 = __posix_fadvise50 */ - { 0, 0, 0, - sys_nosys }, /* 417 = filler */ - { 0, 0, 0, - sys_nosys }, /* 418 = filler */ + { ns(struct sys_openat_args), 0, + (sy_call_t *)sys_openat }, /* 417 = openat */ + { ns(struct sys_fstatat_args), 0, + (sy_call_t *)sys_fstatat }, /* 418 = fstatat */ { 0, 0, 0, sys_nosys }, /* 419 = filler */ { 0, 0, 0, Index: kern/syscalls.c =================================================================== RCS file: /cvsroot/src/sys/kern/syscalls.c,v retrieving revision 1.225 diff -u -p -r1.225 syscalls.c --- kern/syscalls.c 19 Nov 2008 18:40:03 -0000 1.225 +++ kern/syscalls.c 3 Dec 2008 10:51:02 -0000 @@ -1,14 +1,14 @@ -/* $NetBSD: syscalls.c,v 1.225 2008/11/19 18:40:03 ad Exp $ */ +/* $NetBSD$ */ /* * System call names. * * DO NOT EDIT-- this file is automatically generated. - * created from NetBSD: syscalls.master,v 1.216 2008/11/19 18:36:07 ad Exp + * created from NetBSD: syscalls.master,v 1.217 2008/11/21 07:34:46 pooka Exp */ #include -__KERNEL_RCSID(0, "$NetBSD: syscalls.c,v 1.225 2008/11/19 18:40:03 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD$"); #if defined(_KERNEL_OPT) #include "opt_ntp.h" @@ -496,4 +496,6 @@ const char *const syscallnames[] = { /* 414 */ "pset_assign", /* 415 */ "_pset_bind", /* 416 */ "__posix_fadvise50", + /* 417 */ "openat", + /* 418 */ "fstatat", }; Index: kern/syscalls.master =================================================================== RCS file: /cvsroot/src/sys/kern/syscalls.master,v retrieving revision 1.218 diff -u -p -r1.218 syscalls.master --- kern/syscalls.master 26 Nov 2008 15:01:17 -0000 1.218 +++ kern/syscalls.master 3 Dec 2008 10:51:02 -0000 @@ -795,3 +795,8 @@ id_t second_id, psetid_t psid, psetid_t *opsid); } 416 STD { int sys___posix_fadvise50(int fd, int pad, \ off_t offset, off_t len, int advice); } +; openat() family +417 STD { int sys_openat(int dirfd, const char *path, \ + int flags, ... mode_t mode); } +418 STD { int sys_fstatat(int dirfd, const char *path, \ + struct stat *ub, int flags); } Index: kern/vfs_lookup.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_lookup.c,v retrieving revision 1.111 diff -u -p -r1.111 vfs_lookup.c --- kern/vfs_lookup.c 14 Nov 2008 21:57:14 -0000 1.111 +++ kern/vfs_lookup.c 3 Dec 2008 10:51:02 -0000 @@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c #include #include #include +#include #ifndef MAGICLINKS #define MAGICLINKS 0 @@ -220,8 +221,9 @@ namei(struct nameidata *ndp) struct iovec aiov; /* uio for reading symbolic links */ struct lwp *l = curlwp; /* thread doing namei() */ struct uio auio; - int error, linklen; + int error, linklen, fd; struct componentname *cnp = &ndp->ni_cnd; + file_t *fp; #ifdef DIAGNOSTIC if (!cnp->cn_cred) @@ -257,7 +259,6 @@ namei(struct nameidata *ndp) ndp->ni_vp = NULL; return (error); } - ndp->ni_loopcnt = 0; /* * Get root directory for the translation. @@ -293,12 +294,35 @@ namei(struct nameidata *ndp) } else { ndp->ni_erootdir = NULL; } + VREF(dp); + rw_exit(&cwdi->cwdi_lock); + } else if (__predict_false(cnp->cn_flags & STARTATFD) != 0) { + /* + * We put this here, otherwise the caller needs to handle + * refrence counting on vnodes/files (error prone). Note, + * holding references to more than one file at once is + * dangerous because we could deadlock. + */ + rw_exit(&cwdi->cwdi_lock); + fd = ndp->ni_loopcnt; + fp = fd_getfile(fd); + if (__predict_false(fp == NULL)) { + return EBADF; + } + dp = fp->f_data; + if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) { + fd_putfile(fd); + return ENOTDIR; + } + ndp->ni_erootdir = NULL; + VREF(dp); + fd_putfile(fd); } else { dp = cwdi->cwdi_cdir; ndp->ni_erootdir = NULL; + VREF(dp); + rw_exit(&cwdi->cwdi_lock); } - VREF(dp); - rw_exit(&cwdi->cwdi_lock); if (ktrpoint(KTR_NAMEI)) { if (ndp->ni_erootdir != NULL) { @@ -323,7 +347,7 @@ namei(struct nameidata *ndp) vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); /* Loop through symbolic links */ - for (;;) { + for (ndp->ni_loopcnt = 0;;) { if (!dp->v_mount) { /* Give up if the directory is no longer mounted */ vput(dp); Index: kern/vfs_syscalls.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.381 diff -u -p -r1.381 vfs_syscalls.c --- kern/vfs_syscalls.c 19 Nov 2008 18:36:07 -0000 1.381 +++ kern/vfs_syscalls.c 3 Dec 2008 10:51:03 -0000 @@ -1297,34 +1297,27 @@ change_dir(struct nameidata *ndp, struct * Check permissions, allocate an open file structure, * and call the device open routine if any. */ -int -sys_open(struct lwp *l, const struct sys_open_args *uap, register_t *retval) +static int +do_open(struct nameidata *ndp, int flags, int mode, register_t *retval) { - /* { - syscallarg(const char *) path; - syscallarg(int) flags; - syscallarg(int) mode; - } */ - struct proc *p = l->l_proc; + lwp_t *l = curlwp; + proc_t *p = l->l_proc; struct cwdinfo *cwdi = p->p_cwdi; file_t *fp; struct vnode *vp; - int flags, cmode; + int cmode; int type, indx, error; struct flock lf; - struct nameidata nd; - flags = FFLAGS(SCARG(uap, flags)); + flags = FFLAGS(flags); if ((flags & (FREAD | FWRITE)) == 0) return (EINVAL); if ((error = fd_allocfile(&fp, &indx)) != 0) return (error); /* We're going to read cwdi->cwdi_cmask unlocked here. */ - cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT; - NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, - SCARG(uap, path)); + cmode = ((mode &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT; l->l_dupfd = -indx - 1; /* XXX check for fdopen */ - if ((error = vn_open(&nd, flags, cmode)) != 0) { + if ((error = vn_open(ndp, flags, cmode)) != 0) { fd_abort(p, fp, indx); if ((error == EDUPFD || error == EMOVEFD) && l->l_dupfd >= 0 && /* XXX from fdopen */ @@ -1339,7 +1332,7 @@ sys_open(struct lwp *l, const struct sys } l->l_dupfd = 0; - vp = nd.ni_vp; + vp = ndp->ni_vp; fp->f_flag = flags & FMASK; fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; @@ -1371,6 +1364,39 @@ sys_open(struct lwp *l, const struct sys return (0); } +int +sys_open(struct lwp *l, const struct sys_open_args *uap, register_t *retval) +{ + /* { + syscallarg(const char *) path; + syscallarg(int) flags; + syscallarg(int) mode; + } */ + struct nameidata nd; + + NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, + SCARG(uap, path)); + + return do_open(&nd, SCARG(uap, flags), SCARG(uap, mode), retval); +} + +int +sys_openat(struct lwp *l, const struct sys_openat_args *uap, register_t *retval) +{ + /* { + syscallarg(int) dirfd; + syscallarg(const char *) path; + syscallarg(int) flags; + syscallarg(int) mode; + } */ + struct nameidata nd; + + NDINIT_ATFD(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, + SCARG(uap, path), SCARG(uap, dirfd)); + + return do_open(&nd, SCARG(uap, flags), SCARG(uap, mode), retval); +} + static void vfs__fhfree(fhandle_t *fhp) { @@ -2455,6 +2481,41 @@ sys___lstat30(struct lwp *l, const struc } /* + * Get file status; this version does configurable lookups. + */ +/* ARGSUSED */ +int +sys_fstatat(struct lwp *l, const struct sys_fstatat_args *uap, register_t *retval) +{ + /* { + syscallarg(int) dirfd; + syscallarg(const char *) path; + syscallarg(struct stat *) ub; + syscallarg(int) flags; + } */ + struct stat sb; + struct nameidata nd; + int error, nd_flags; + + if ((SCARG(uap, flags) & AT_SYMLINK_NOFOLLOW) != 0) { + nd_flags = NOFOLLOW | LOCKLEAF | TRYEMULROOT; + } else { + nd_flags = FOLLOW | LOCKLEAF | TRYEMULROOT; + } + + NDINIT_ATFD(&nd, LOOKUP, nd_flags, UIO_USERSPACE, SCARG(uap, path), + SCARG(uap, dirfd)); + error = namei(&nd); + if (error != 0) + return error; + error = vn_stat(nd.ni_vp, &sb); + vput(nd.ni_vp); + if (error == 0) + error = copyout(&sb, SCARG(uap, ub), sizeof(sb)); + return error; +} + +/* * Get configurable pathname variables. */ /* ARGSUSED */ Index: sys/fcntl.h =================================================================== RCS file: /cvsroot/src/sys/sys/fcntl.h,v retrieving revision 1.34 diff -u -p -r1.34 fcntl.h --- sys/fcntl.h 5 Oct 2006 14:48:33 -0000 1.34 +++ sys/fcntl.h 3 Dec 2008 10:51:03 -0000 @@ -246,6 +246,12 @@ struct flock { #define LOCK_EX 0x02 /* exclusive file lock */ #define LOCK_NB 0x04 /* don't block when locking */ #define LOCK_UN 0x08 /* unlock file */ + +/* flags to the openat() family of calls */ +#define AT_FDCWD -100 /* use working directory */ +#define AT_SYMLINK_NOFOLLOW 0x100 /* do not follow symlinks */ +#define AT_REMOVEDIR 0x200 /* remove dir, not file */ +#define AT_SYMLINK_FOLLOW 0x400 /* follow symbolic links */ #endif /* Always ensure that these are consistent with and ! */ @@ -278,6 +284,7 @@ int open(const char *, int, ...); int creat(const char *, mode_t); int fcntl(int, int, ...); #if defined(_NETBSD_SOURCE) +int openat(int, const char *, int, ...); int flock(int, int); #endif /* _NETBSD_SOURCE */ int posix_fadvise(int, off_t, off_t, int); Index: sys/namei.h =================================================================== RCS file: /cvsroot/src/sys/sys/namei.h,v retrieving revision 1.63 diff -u -p -r1.63 namei.h --- sys/namei.h 17 Nov 2008 07:20:54 -0000 1.63 +++ sys/namei.h 3 Dec 2008 10:51:04 -0000 @@ -1,9 +1,10 @@ -/* $NetBSD: namei.h,v 1.63 2008/11/17 07:20:54 pooka Exp $ */ +/* $NetBSD$ */ + /* * WARNING: GENERATED FILE. DO NOT EDIT - * (edit namei.src and run make namei) - * by: NetBSD: gennameih.awk,v 1.2 2008/04/30 13:11:00 martin Exp + * (edit namei.src and run make namei in src/sys/sys) + * by: NetBSD: gennameih.awk,v 1.3 2008/11/17 08:47:20 pooka Exp * from: NetBSD: namei.src,v 1.9 2008/11/17 07:20:37 pooka Exp */ @@ -112,6 +115,7 @@ struct nameidata { #define NOCHROOT 0x0010 /* no chroot on abs path lookups */ #define NOCACHE 0x0020 /* name must not be left in cache */ #define FOLLOW 0x0040 /* follow symbolic links */ +#define STARTATFD 0x0080 /* root directory given */ #define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */ #define TRYEMULROOT 0x0010 /* try relative to emulation root first */ #define EMULROOTSET 0x0080 /* emulation root already in ni_erootdir */ @@ -155,6 +159,15 @@ struct nameidata { (ndp)->ni_dirp = namep; \ (ndp)->ni_cnd.cn_cred = kauth_cred_get(); \ } + +#define NDINIT_ATFD(ndp, op, flags, segflg, namep, fd) { \ + int _ndinit_flags = (flags); \ + if (fd != AT_FDCWD) { \ + _ndinit_flags |= STARTATFD; \ + (ndp)->ni_loopcnt = fd; \ + } \ + NDINIT(ndp, op, _ndinit_flags, segflg, namep) \ +} #endif /* @@ -254,6 +267,7 @@ extern struct nchstats nchstats; #define NAMEI_NOCHROOT 0x0010 #define NAMEI_NOCACHE 0x0020 #define NAMEI_FOLLOW 0x0040 +#define NAMEI_STARTATFD 0x0080 #define NAMEI_NOFOLLOW 0x0000 #define NAMEI_TRYEMULROOT 0x0010 #define NAMEI_EMULROOTSET 0x0080 Index: sys/namei.src =================================================================== RCS file: /cvsroot/src/sys/sys/namei.src,v retrieving revision 1.9 diff -u -p -r1.9 namei.src --- sys/namei.src 17 Nov 2008 07:20:37 -0000 1.9 +++ sys/namei.src 3 Dec 2008 10:51:04 -0000 @@ -105,6 +107,7 @@ NAMEIFL LOCKPARENT 0x0008 /* want parent NAMEIFL NOCHROOT 0x0010 /* no chroot on abs path lookups */ NAMEIFL NOCACHE 0x0020 /* name must not be left in cache */ NAMEIFL FOLLOW 0x0040 /* follow symbolic links */ +NAMEIFL STARTATFD 0x0080 /* root directory given */ NAMEIFL NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */ NAMEIFL TRYEMULROOT 0x0010 /* try relative to emulation root first */ NAMEIFL EMULROOTSET 0x0080 /* emulation root already in ni_erootdir */ @@ -148,6 +151,15 @@ NAMEIFL PARAMASK 0x02fff00 /* mask of pa (ndp)->ni_dirp = namep; \ (ndp)->ni_cnd.cn_cred = kauth_cred_get(); \ } + +#define NDINIT_ATFD(ndp, op, flags, segflg, namep, fd) { \ + int _ndinit_flags = (flags); \ + if (fd != AT_FDCWD) { \ + _ndinit_flags |= STARTATFD; \ + (ndp)->ni_loopcnt = fd; \ + } \ + NDINIT(ndp, op, _ndinit_flags, segflg, namep) \ +} #endif /* Index: sys/stat.h =================================================================== RCS file: /cvsroot/src/sys/sys/stat.h,v retrieving revision 1.57 diff -u -p -r1.57 stat.h --- sys/stat.h 31 Jul 2008 05:38:06 -0000 1.57 +++ sys/stat.h 3 Dec 2008 10:51:04 -0000 @@ -249,6 +249,7 @@ int mknod(const char *, mode_t, dev_t); #if defined(_NETBSD_SOURCE) int chflags(const char *, unsigned long); int fchflags(int, unsigned long); +int fstatat(int, const char *, struct stat *, int); int lchflags(const char *, unsigned long); int lchmod(const char *, mode_t); #endif /* defined(_NETBSD_SOURCE) */ Index: sys/syscall.h =================================================================== RCS file: /cvsroot/src/sys/sys/syscall.h,v retrieving revision 1.222 diff -u -p -r1.222 syscall.h --- sys/syscall.h 19 Nov 2008 18:40:02 -0000 1.222 +++ sys/syscall.h 3 Dec 2008 10:51:04 -0000 @@ -1,10 +1,10 @@ -/* $NetBSD: syscall.h,v 1.222 2008/11/19 18:40:02 ad Exp $ */ +/* $NetBSD$ */ /* * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * created from NetBSD: syscalls.master,v 1.216 2008/11/19 18:36:07 ad Exp + * created from NetBSD: syscalls.master,v 1.217 2008/11/21 07:34:46 pooka Exp */ #ifndef _SYS_SYSCALL_H_ @@ -1162,6 +1162,12 @@ /* syscall: "__posix_fadvise50" ret: "int" args: "int" "int" "off_t" "off_t" "int" */ #define SYS___posix_fadvise50 416 -#define SYS_MAXSYSCALL 417 +/* syscall: "openat" ret: "int" args: "int" "const char *" "int" "..." */ +#define SYS_openat 417 + +/* syscall: "fstatat" ret: "int" args: "int" "const char *" "struct stat *" "int" */ +#define SYS_fstatat 418 + +#define SYS_MAXSYSCALL 419 #define SYS_NSYSENT 512 #endif /* _SYS_SYSCALL_H_ */ Index: sys/syscallargs.h =================================================================== RCS file: /cvsroot/src/sys/sys/syscallargs.h,v retrieving revision 1.204 diff -u -p -r1.204 syscallargs.h --- sys/syscallargs.h 19 Nov 2008 18:40:03 -0000 1.204 +++ sys/syscallargs.h 3 Dec 2008 10:51:04 -0000 @@ -1,10 +1,10 @@ -/* $NetBSD: syscallargs.h,v 1.204 2008/11/19 18:40:03 ad Exp $ */ +/* $NetBSD$ */ /* * System call argument lists. * * DO NOT EDIT-- this file is automatically generated. - * created from NetBSD: syscalls.master,v 1.216 2008/11/19 18:36:07 ad Exp + * created from NetBSD: syscalls.master,v 1.217 2008/11/21 07:34:46 pooka Exp */ #ifndef _SYS_SYSCALLARGS_H_ @@ -2270,6 +2270,22 @@ struct sys___posix_fadvise50_args { }; check_syscall_args(sys___posix_fadvise50) +struct sys_openat_args { + syscallarg(int) dirfd; + syscallarg(const char *) path; + syscallarg(int) flags; + syscallarg(mode_t) mode; +}; +check_syscall_args(sys_openat) + +struct sys_fstatat_args { + syscallarg(int) dirfd; + syscallarg(const char *) path; + syscallarg(struct stat *) ub; + syscallarg(int) flags; +}; +check_syscall_args(sys_fstatat) + /* * System call prototypes. */ @@ -3029,4 +3045,8 @@ int sys__pset_bind(struct lwp *, const s int sys___posix_fadvise50(struct lwp *, const struct sys___posix_fadvise50_args *, register_t *); +int sys_openat(struct lwp *, const struct sys_openat_args *, register_t *); + +int sys_fstatat(struct lwp *, const struct sys_fstatat_args *, register_t *); + #endif /* _SYS_SYSCALLARGS_H_ */