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 <sys/cdefs.h>
-__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 <sys/cdefs.h>
-__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 <sys/syslog.h>
 #include <sys/kauth.h>
 #include <sys/ktrace.h>
+#include <sys/file.h>
 
 #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 <stdio.h> and <unistd.h>! */
@@ -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_ */