---  amd64/linux32/linux.h.orig
+++  amd64/linux32/linux.h
@@ -566,8 +566,6 @@
 #define	LINUX_F_WRLCK		1
 #define	LINUX_F_UNLCK		2
 
-#define	LINUX_AT_FDCWD		-100
-
 /*
  * mount flags
  */
---  amd64/linux32/linux32_dummy.c.orig
+++  amd64/linux32/linux32_dummy.c
@@ -96,18 +96,6 @@
 DUMMY(inotify_add_watch);
 DUMMY(inotify_rm_watch);
 DUMMY(migrate_pages);
-DUMMY(mkdirat);
-DUMMY(mknodat);
-DUMMY(fchownat);
-DUMMY(futimesat);
-DUMMY(fstatat64);
-DUMMY(unlinkat);
-DUMMY(renameat);
-DUMMY(linkat);
-DUMMY(symlinkat);
-DUMMY(readlinkat);
-DUMMY(fchmodat);
-DUMMY(faccessat);
 DUMMY(pselect6);
 DUMMY(ppoll);
 DUMMY(unshare);
---  amd64/linux32/linux32_proto.h.orig
+++  amd64/linux32/linux32_proto.h
@@ -2,7 +2,7 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/amd64/linux32/linux32_proto.h,v 1.31 2007/03/30 00:08:21 jkim Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp 
  */
 
@@ -875,45 +875,77 @@
 };
 struct linux_openat_args {
 	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
-	char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
 	char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
 	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mkdirat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mknodat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
+	char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)];
 };
 struct linux_fchownat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)];
+	char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_futimesat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
+	char utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)];
 };
 struct linux_fstatat64_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)];
+	char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_unlinkat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_renameat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)];
 };
 struct linux_linkat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)];
+	char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
 };
 struct linux_symlinkat_args {
-	register_t dummy;
+	char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)];
 };
 struct linux_readlinkat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+	char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)];
 };
 struct linux_fchmodat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)];
 };
 struct linux_faccessat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_pselect6_args {
 	register_t dummy;
---  amd64/linux32/linux32_syscall.h.orig
+++  amd64/linux32/linux32_syscall.h
@@ -2,7 +2,7 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/amd64/linux32/linux32_syscall.h,v 1.31 2007/03/30 00:08:21 jkim Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp 
  */
 
---  amd64/linux32/linux32_sysent.c.orig
+++  amd64/linux32/linux32_sysent.c
@@ -2,7 +2,7 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/amd64/linux32/linux32_sysent.c,v 1.31 2007/03/30 00:08:21 jkim Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp 
  */
 
@@ -316,18 +316,18 @@
 	{ 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0 },	/* 293 = linux_inotify_rm_watch */
 	{ 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0 },	/* 294 = linux_migrate_pages */
 	{ AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0 },	/* 295 = linux_openat */
-	{ 0, (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
-	{ 0, (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
-	{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
-	{ 0, (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
-	{ 0, (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
-	{ 0, (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
-	{ 0, (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
-	{ 0, (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
-	{ 0, (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
-	{ 0, (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
-	{ 0, (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
-	{ 0, (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
+	{ AS(linux_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
+	{ AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
+	{ AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
+	{ AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
+	{ AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
+	{ AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
+	{ AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
+	{ AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
+	{ AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
+	{ AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
+	{ AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
+	{ AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
 	{ 0, (sy_call_t *)linux_pselect6, AUE_NULL, NULL, 0, 0 },	/* 308 = linux_pselect6 */
 	{ 0, (sy_call_t *)linux_ppoll, AUE_NULL, NULL, 0, 0 },	/* 309 = linux_ppoll */
 	{ 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0 },	/* 310 = linux_unshare */
---  amd64/linux32/linux32_sysvec.c.orig
+++  amd64/linux32/linux32_sysvec.c
@@ -43,6 +43,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/exec.h>
+#include <sys/fcntl.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 #include <sys/kernel.h>
@@ -787,7 +788,7 @@
 	     */
 	    if ((error = exec_shell_imgact(imgp)) == 0) {
 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
-			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
+			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
 		    if (rpath != NULL) {
 			    len = strlen(rpath) + 1;
 
---  amd64/linux32/syscalls.master.orig
+++  amd64/linux32/syscalls.master
@@ -463,20 +463,31 @@
 292	AUE_NULL	STD	{ int linux_inotify_add_watch(void); }
 293	AUE_NULL	STD	{ int linux_inotify_rm_watch(void); }
 294	AUE_NULL	STD	{ int linux_migrate_pages(void); }
-295	AUE_OPEN_RWTC	STD	{ int linux_openat(l_int dfd, char *filename, \
+295	AUE_OPEN_RWTC	STD	{ int linux_openat(l_int dfd, const char *filename, \
 					l_int flags, l_int mode); }
-296	AUE_NULL	STD	{ int linux_mkdirat(void); }
-297	AUE_NULL	STD	{ int linux_mknodat(void); }
-298	AUE_NULL	STD	{ int linux_fchownat(void); }
-299	AUE_NULL	STD	{ int linux_futimesat(void); }
-300	AUE_NULL	STD	{ int linux_fstatat64(void); }
-301	AUE_NULL	STD	{ int linux_unlinkat(void); }
-302	AUE_NULL	STD	{ int linux_renameat(void); }
-303	AUE_NULL	STD	{ int linux_linkat(void); }
-304	AUE_NULL	STD	{ int linux_symlinkat(void); }
-305	AUE_NULL	STD	{ int linux_readlinkat(void); }
-306	AUE_NULL	STD	{ int linux_fchmodat(void); }
-307	AUE_NULL	STD	{ int linux_faccessat(void); }
+296	AUE_NULL	STD	{ int linux_mkdirat(l_int dfd, const char *pathname, \
+					l_int mode); }
+297	AUE_NULL	STD	{ int linux_mknodat(l_int dfd, const char *filename, \
+					l_int mode, l_uint dev); }
+298	AUE_NULL	STD	{ int linux_fchownat(l_int dfd, const char *filename, \
+					l_uid16_t uid, l_gid16_t gid, l_int flag); }
+299	AUE_NULL	STD	{ int linux_futimesat(l_int dfd, char *filename, \
+					struct l_timeval *utimes); }
+300	AUE_NULL	STD	{ int linux_fstatat64(l_int dfd, char *pathname, \
+					struct l_stat64 *statbuf, l_int flag); }
+301	AUE_NULL	STD	{ int linux_unlinkat(l_int dfd, const char *pathname, \
+					l_int flag); }
+302	AUE_NULL	STD	{ int linux_renameat(l_int olddfd, const char *oldname, \
+					l_int newdfd, const char *newname); }
+303	AUE_NULL	STD	{ int linux_linkat(l_int olddfd, const char *oldname, \
+					l_int newdfd, const char *newname, l_int flags); }
+304	AUE_NULL	STD	{ int linux_symlinkat(const char *oldname, l_int newdfd, \
+					const char *newname); }
+305	AUE_NULL	STD	{ int linux_readlinkat(l_int dfd, const char *path, \
+					char *buf, l_int bufsiz); }
+306	AUE_NULL	STD	{ int linux_fchmodat(l_int dfd, const char *filename, \
+					l_mode_t mode); }
+307	AUE_NULL	STD	{ int linux_faccessat(l_int dfd, const char *filename, l_int mode); }
 308	AUE_NULL	STD	{ int linux_pselect6(void); }
 309	AUE_NULL	STD	{ int linux_ppoll(void); }
 310	AUE_NULL	STD	{ int linux_unshare(void); }
---  compat/linux/linux_file.c.orig
+++  compat/linux/linux_file.c
@@ -67,6 +67,7 @@
 #include <machine/../linux/linux_proto.h>
 #endif
 #include <compat/linux/linux_util.h>
+#include <compat/linux/linux_file.h>
 
 int
 linux_creat(struct thread *td, struct linux_creat_args *args)
@@ -88,7 +89,7 @@
 
 
 static int
-linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat)
+linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
 {
     struct proc *p = td->td_proc;
     struct file *fp;
@@ -130,7 +131,10 @@
 	bsd_flags |= O_NOFOLLOW;
     /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
 
-    error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
+    if (dirfd != -1)
+	error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
+    else
+	error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
     if (!error) {
 	    fd = td->td_retval[0];
 	    /*
@@ -172,115 +176,33 @@
     if (ldebug(open))
 	    printf(LMSG("open returns error %d"), error);
 #endif
-    if (!openat)
-	LFREEPATH(path);
+    LFREEPATH(path);
     return error;
 }
 
-/*
- * common code for linux *at set of syscalls
- *
- * works like this:
- * if filename is absolute 
- *    ignore dirfd
- * else
- *    if dirfd == AT_FDCWD 
- *       return CWD/filename
- *    else
- *       return DIRFD/filename
- */
-static int
-linux_at(struct thread *td, int dirfd, char *filename, char **newpath, char **freebuf)
-{
-   	struct file *fp;
-	int error = 0, vfslocked;
-	struct vnode *dvp;
-	struct filedesc *fdp = td->td_proc->p_fd;
-	char *fullpath = "unknown";
-	char *freepath = NULL;
-
-	/* don't do anything if the pathname is absolute */
-	if (*filename == '/') {
-	   	*newpath= filename;
-	   	return (0);
-	}
-
-	/* check for AT_FDWCD */
-	if (dirfd == LINUX_AT_FDCWD) {
-	   	FILEDESC_SLOCK(fdp);
-		dvp = fdp->fd_cdir;
-		vref(dvp);
-	   	FILEDESC_SUNLOCK(fdp);
-	} else {
-	   	error = fget(td, dirfd, &fp);
-		if (error)
-		   	return (error);
-		dvp = fp->f_vnode;
-		/* only a dir can be dfd */
-		if (dvp->v_type != VDIR) {
-		   	fdrop(fp, td);
-			return (ENOTDIR);
-		}
-		vref(dvp);
-		fdrop(fp, td);
-	}
-
-	/*
-	 * XXXRW: This is bogus, as vn_fullpath() returns only an advisory
-	 * file path, and may fail in several common situations, including
-	 * for file systmes that don't use the name cache, and if the entry
-	 * for the file falls out of the name cache.  We should implement
-	 * openat() in the FreeBSD native system call layer properly (using a
-	 * requested starting directory), and have Linux and other ABIs wrap
-	 * the native implementation.
-	 */
-	error = vn_fullpath(td, dvp, &fullpath, &freepath);
-	if (!error) {
-	   	*newpath = malloc(strlen(fullpath) + strlen(filename) + 2, M_TEMP, M_WAITOK | M_ZERO);
-		*freebuf = freepath;
-		sprintf(*newpath, "%s/%s", fullpath, filename);
-	} else {
-		*newpath = NULL;
-	}
-	vfslocked = VFS_LOCK_GIANT(dvp->v_mount);
-	vrele(dvp);
-	VFS_UNLOCK_GIANT(vfslocked);
-	return (error);
-}
-
 int
 linux_openat(struct thread *td, struct linux_openat_args *args)
 {
-   	char *newpath, *oldpath, *freebuf = NULL, *path;
-	int error;
+   	char *path;
+	int dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
 
-	oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-	error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL);
+    	if (args->flags & LINUX_O_CREAT)
+		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
+    	else
+		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
 
 #ifdef DEBUG
 	if (ldebug(openat))
 		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
-		    oldpath, args->flags, args->mode);
+		    path, args->flags, args->mode);
 #endif
 
-	error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf);
-	if (error)
-	   	return (error);
-#ifdef DEBUG
-	printf(LMSG("newpath: %s"), newpath);
-#endif
-    	if (args->flags & LINUX_O_CREAT)
-		LCONVPATH_SEG(td, newpath, &path, 1, UIO_SYSSPACE);
-    	else
-		LCONVPATH_SEG(td, newpath, &path, 0, UIO_SYSSPACE);
-	if (freebuf)
-	   	free(freebuf, M_TEMP);
-	if (*oldpath != '/')
-   	   	free(newpath, M_TEMP);
-
-	error = linux_common_open(td, path, args->flags, args->mode, 1);
-	free(oldpath, M_TEMP);
-	return (error);
+	return linux_common_open(td, dfd, path, args->flags, args->mode);
 }
 
 int
@@ -299,7 +221,7 @@
 		    path, args->flags, args->mode);
 #endif
 
-    return linux_common_open(td, path, args->flags, args->mode, 0);
+    return linux_common_open(td, -1, path, args->flags, args->mode);
 }
 
 int
@@ -649,6 +571,34 @@
 }
 
 int
+linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	/* linux convention */
+	if (args->mode & ~(F_OK | X_OK | W_OK | R_OK))
+		return (EINVAL);
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = -1;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(access))
+		printf(ARGS(access, "%s, %d"), path, args->mode);
+#endif
+
+	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, args->mode);
+	LFREEPATH(path);
+
+	return (error);
+}
+
+int
 linux_unlink(struct thread *td, struct linux_unlink_args *args)
 {
 	char *path;
@@ -673,6 +623,40 @@
 }
 
 int
+linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
+{
+	char *path;
+	int error, dfd;
+	struct stat st;
+
+	if (args->flag & ~LINUX_AT_REMOVEDIR)
+		return (EINVAL);
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(unlinkat))
+		printf(ARGS(unlinkat, "%s"), path);
+#endif
+
+	if (args->flag & LINUX_AT_REMOVEDIR)
+		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
+	else
+		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE);
+	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR))
+		/* Introduce POSIX noncompliant behaviour of Linux */
+		if (kern_statat(td, dfd, path, UIO_SYSSPACE, &st) == 0)
+			if (S_ISDIR(st.st_mode))
+				error = EISDIR;
+	LFREEPATH(path);
+	return (error);
+}
+int
 linux_chdir(struct thread *td, struct linux_chdir_args *args)
 {
 	char *path;
@@ -707,6 +691,29 @@
 }
 
 int
+linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(fchmodat))
+		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
+#endif
+
+	error = kern_chmodat(td, dfd, path, UIO_SYSSPACE, args->mode);
+	LFREEPATH(path);
+	return (error);
+}
+
+int
 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
 {
 	char *path;
@@ -724,6 +731,28 @@
 }
 
 int
+linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(mkdirat))
+		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
+#endif
+	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
+	LFREEPATH(path);
+	return (error);
+}
+
+int
 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
 {
 	char *path;
@@ -748,7 +777,7 @@
 
 	LCONVPATHEXIST(td, args->from, &from);
 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
-	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
+	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 	if (to == NULL) {
 		LFREEPATH(from);
 		return (error);
@@ -765,6 +794,40 @@
 }
 
 int
+linux_renameat(struct thread *td, struct linux_renameat_args *args)
+{
+	char *from, *to;
+	int error, olddfd, newdfd;
+
+	if (args->olddfd == LINUX_AT_FDCWD)
+		olddfd = AT_FDCWD;
+	else
+		olddfd = args->olddfd;
+
+	if (args->newdfd == LINUX_AT_FDCWD)
+		newdfd = AT_FDCWD;
+	else
+		newdfd = args->newdfd;
+
+	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
+	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
+	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
+	if (to == NULL) {
+		LFREEPATH(from);
+		return (error);
+	}
+
+#ifdef DEBUG
+	if (ldebug(renameat))
+		printf(ARGS(renameat, "%s, %s"), from, to);
+#endif
+	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
+	LFREEPATH(from);
+	LFREEPATH(to);
+	return (error);
+}
+
+int
 linux_symlink(struct thread *td, struct linux_symlink_args *args)
 {
 	char *path, *to;
@@ -772,7 +835,7 @@
 
 	LCONVPATHEXIST(td, args->path, &path);
 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
-	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
+	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 	if (to == NULL) {
 		LFREEPATH(path);
 		return (error);
@@ -789,6 +852,36 @@
 }
 
 int
+linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
+{
+	char *path, *to;
+	int error, dfd;
+
+	if (args->newdfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->newdfd;
+
+	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
+	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
+	if (to == NULL) {
+		LFREEPATH(path);
+		return (error);
+	}
+
+#ifdef DEBUG
+	if (ldebug(symlinkat))
+		printf(ARGS(symlinkat, "%s, %s"), path, to);
+#endif
+
+	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
+	LFREEPATH(path);
+	LFREEPATH(to);
+	return (error);
+}
+
+int
 linux_readlink(struct thread *td, struct linux_readlink_args *args)
 {
 	char *name;
@@ -808,6 +901,30 @@
 }
 
 int
+linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
+{
+	char *name;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
+
+#ifdef DEBUG
+	if (ldebug(readlinkat))
+		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
+		    args->bufsiz);
+#endif
+
+	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
+	    UIO_USERSPACE, args->bufsiz);
+	LFREEPATH(name);
+	return (error);
+}
+int
 linux_truncate(struct thread *td, struct linux_truncate_args *args)
 {
 	char *path;
@@ -847,7 +964,7 @@
 
 	LCONVPATHEXIST(td, args->path, &path);
 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
-	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
+	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 	if (to == NULL) {
 		LFREEPATH(path);
 		return (error);
@@ -864,6 +981,49 @@
 }
 
 int
+linux_linkat(struct thread *td, struct linux_linkat_args *args)
+{
+	char *path, *to;
+	int error, olddfd, newdfd;
+
+	/* 
+	 * don't laugh they really introduced flags argument
+	 * which is forbidden to use ;)
+	 */
+	if (args->flags != 0)
+		return (EINVAL);
+
+	if (args->olddfd == LINUX_AT_FDCWD)
+		olddfd = AT_FDCWD;
+	else
+		olddfd = args->olddfd;
+
+	if (args->newdfd == LINUX_AT_FDCWD)
+		newdfd = AT_FDCWD;
+	else
+		newdfd = args->newdfd;
+
+	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
+	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
+	if (to == NULL) {
+		LFREEPATH(path);
+		return (error);
+	}
+
+#ifdef DEBUG
+	if (ldebug(linkat))
+		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
+			args->newdfd, to, args->flags);
+#endif
+
+	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, FOLLOW);
+	LFREEPATH(path);
+	LFREEPATH(to);
+	return (error);
+}
+
+int
 linux_fdatasync(td, uap)
 	struct thread *td;
 	struct linux_fdatasync_args *uap;
@@ -1329,6 +1489,35 @@
 }
 
 int
+linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);	
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(fchownat))
+		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
+#endif
+
+	if (args->flag & LINUX_AT_SYMLINK_NOFOLLOW)
+		error = kern_lchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid);
+	else
+		error = kern_chownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid);
+	LFREEPATH(path);
+	return (error);
+}
+
+int
 linux_lchown(struct thread *td, struct linux_lchown_args *args)
 {
 	char *path;
--- /dev/null	Thu Jul  5 15:22:00 2007
+++ compat/linux/linux_file.h	Thu Jul  5 15:22:39 2007
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_FILE_H_
+#define	_LINUX_FILE_H_
+
+#define	LINUX_AT_FDCWD			-100
+#define	LINUX_AT_SYMLINK_NOFOLLOW	0x100
+#define	LINUX_AT_REMOVEDIR		0x200
+
+#endif	/* !_LINUX_FILE_H_ */
--- compat/linux/linux_misc.c.orig
+++ compat/linux/linux_misc.c
@@ -86,6 +86,7 @@
 #include <machine/../linux/linux_proto.h>
 #endif
 
+#include <compat/linux/linux_file.h>
 #include <compat/linux/linux_mib.h>
 #include <compat/linux/linux_signal.h>
 #include <compat/linux/linux_util.h>
@@ -820,6 +821,43 @@
 	LFREEPATH(fname);
 	return (error);
 }
+
+int
+linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
+{
+	l_timeval ltv[2];
+	struct timeval tv[2], *tvp = NULL;
+	char *fname;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
+
+#ifdef DEBUG
+	if (ldebug(futimesat))
+		printf(ARGS(futimesat, "%s, *"), fname);
+#endif
+
+	if (args->utimes != NULL) {
+		if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
+			LFREEPATH(fname);
+			return (error);
+		}
+		tv[0].tv_sec = ltv[0].tv_sec;
+		tv[0].tv_usec = ltv[0].tv_usec;
+		tv[1].tv_sec = ltv[1].tv_sec;
+		tv[1].tv_usec = ltv[1].tv_usec;
+		tvp = tv;
+	}
+
+	error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
+	LFREEPATH(fname);
+	return (error);
+}
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 #define __WCLONE 0x80000000
@@ -947,6 +985,60 @@
 	case S_IFREG:
 		error = kern_open(td, path, UIO_SYSSPACE,
 		    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
+		if (error == 0)
+			kern_close(td, td->td_retval[0]);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+	LFREEPATH(path);
+	return (error);
+}
+
+int
+linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHCREAT_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(mknodat))
+		printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev);
+#endif
+
+	switch (args->mode & S_IFMT) {
+	case S_IFIFO:
+	case S_IFSOCK:
+		error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode);
+		break;
+
+	case S_IFCHR:
+	case S_IFBLK:
+		error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode,
+		    args->dev);
+		break;
+
+	case S_IFDIR:
+		error = EPERM;
+		break;
+
+	case 0:
+		args->mode |= S_IFREG;
+		/* FALLTHROUGH */
+	case S_IFREG:
+		error = kern_openat(td, dfd, path, UIO_SYSSPACE,
+		    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
+		if (error == 0)
+			kern_close(td, td->td_retval[0]);
 		break;
 
 	default:
--- compat/linux/linux_stats.c.orig
+++ compat/linux/linux_stats.c
@@ -57,6 +57,7 @@
 #endif
 
 #include <compat/linux/linux_util.h>
+#include <compat/linux/linux_file.h>
 
 #include <security/mac/mac_framework.h>
 
@@ -132,6 +133,26 @@
 	fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
 }
 
+static void
+translate_path_major_minor_at(struct thread *td, char *path, struct stat *buf,
+    int dfd)
+{
+	struct proc *p = td->td_proc;	
+	struct filedesc *fdp = p->p_fd;
+	int fd;
+	int temp;
+
+	if (!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode))
+		return;
+	temp = td->td_retval[0];
+	if (kern_openat(td, dfd, path, UIO_SYSSPACE, O_RDONLY, 0) != 0)
+		return;
+	fd = td->td_retval[0];
+	td->td_retval[0] = temp;
+	translate_fd_major_minor(td, fd, buf);
+	fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
+}
+
 static int
 newstat_copyout(struct stat *buf, void *ubuf)
 {
@@ -578,4 +599,39 @@
 	return (error);
 }
 
+int
+linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
+{
+	char *path;
+	int error, dfd;
+	struct stat buf;
+
+	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(fstatat64))
+		printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
+#endif
+
+	if (args->flag & LINUX_AT_SYMLINK_NOFOLLOW)
+		error = kern_lstatat(td, dfd, path, UIO_SYSSPACE, &buf);
+	else
+		error = kern_statat(td, dfd, path, UIO_SYSSPACE, &buf);
+		
+	translate_path_major_minor_at(td, args->pathname, &buf, dfd);
+	if (!error)
+		error = stat64_copyout(&buf, args->statbuf);
+	LFREEPATH(path);
+	
+	return (error);
+}
+
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
--- compat/linux/linux_uid16.c.orig
+++ compat/linux/linux_uid16.c
@@ -29,6 +29,7 @@
 
 #include "opt_compat.h"
 
+#include <sys/fcntl.h>
 #include <sys/param.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
--- compat/linux/linux_util.c.orig
+++ compat/linux/linux_util.c
@@ -36,6 +36,7 @@
 
 #include <sys/param.h>
 #include <sys/bus.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/linker_set.h>
@@ -65,16 +66,17 @@
  * named file, i.e. we check if the directory it should be in exists.
  */
 int
-linux_emul_convpath(td, path, pathseg, pbuf, cflag)
+linux_emul_convpath(td, path, pathseg, pbuf, cflag, dfd)
 	struct thread	 *td;
-	char		 *path;
+	const char	 *path;
 	enum uio_seg	  pathseg;
 	char		**pbuf;
 	int		  cflag;
+	int		  dfd;		
 {
 
-	return (kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
-		cflag));
+	return kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
+		cflag, dfd);
 }
 
 void
--- compat/linux/linux_util.h.orig
+++ compat/linux/linux_util.h
@@ -51,23 +51,25 @@
 
 extern const char linux_emul_path[];
 
-int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int);
+int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, int, int);
 
-#define LCONVPATH_SEG(td, upath, pathp, i, seg)				\
+#define LCONVPATH_AT(td, upath, pathp, i, dfd)				\
 	do {								\
 		int _error;						\
 									\
-		_error = linux_emul_convpath(td, upath, seg,		\
-		    pathp, i);						\
+		_error = linux_emul_convpath(td, upath, UIO_USERSPACE,	\
+		    pathp, i, dfd);					\
 		if (*(pathp) == NULL)					\
 			return (_error);				\
 	} while (0)
 
 #define LCONVPATH(td, upath, pathp, i) 	\
-   LCONVPATH_SEG(td, upath, pathp, i, UIO_USERSPACE)
+   LCONVPATH_AT(td, upath, pathp, i, AT_FDCWD)
 
 #define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
+#define LCONVPATHEXIST_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 0, dfd)
 #define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
+#define LCONVPATHCREAT_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 1, dfd)
 #define LFREEPATH(path)	free(path, M_TEMP)
 
 #define DUMMY(s)							\
--- compat/svr4/svr4_sysvec.c.orig
+++ compat/svr4/svr4_sysvec.c
@@ -44,6 +44,7 @@
 #include <sys/sysent.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -258,7 +259,7 @@
 {
 
 	return (kern_alternate_path(td, svr4_emul_path, path, pathseg, pbuf,
-	    create));
+	    create, AT_FDCWD));
 }
 
 static int
--- i386/ibcs2/ibcs2_util.c.orig
+++ i386/ibcs2/ibcs2_util.c
@@ -32,6 +32,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/i386/ibcs2/ibcs2_util.c,v 1.19 2005/02/07 22:02:18 jhb Exp $");
 
+#include <sys/fcntl.h>
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/syscallsubr.h>
@@ -55,5 +56,5 @@
 {
 
 	return (kern_alternate_path(td, ibcs2_emul_path, path, pathseg, pbuf,
-	    cflag));
+	    cflag, AT_FDCWD));
 }
--- i386/linux/linux.h.orig
+++ i386/linux/linux.h
@@ -537,8 +537,6 @@
 #define	LINUX_F_WRLCK		1
 #define	LINUX_F_UNLCK		2
 
-#define	LINUX_AT_FDCWD		-100
-
 /*
  * mount flags
  */
--- i386/linux/linux_dummy.c.orig
+++ i386/linux/linux_dummy.c
@@ -87,18 +87,6 @@
 DUMMY(inotify_add_watch);
 DUMMY(inotify_rm_watch);
 DUMMY(migrate_pages);
-DUMMY(mkdirat);
-DUMMY(mknodat);
-DUMMY(fchownat);
-DUMMY(futimesat);
-DUMMY(fstatat64);
-DUMMY(unlinkat);
-DUMMY(renameat);
-DUMMY(linkat);
-DUMMY(symlinkat);
-DUMMY(readlinkat);
-DUMMY(fchmodat);
-DUMMY(faccessat);
 DUMMY(pselect6);
 DUMMY(ppoll);
 DUMMY(unshare);
--- i386/linux/linux_proto.h.orig
+++ i386/linux/linux_proto.h
@@ -2,8 +2,8 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/i386/linux/linux_proto.h,v 1.92 2007/03/29 02:11:46 julian Exp $
- * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -894,45 +894,77 @@
 };
 struct linux_openat_args {
 	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
-	char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
 	char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
 	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mkdirat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mknodat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
+	char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)];
 };
 struct linux_fchownat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)];
+	char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_futimesat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
+	char utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)];
 };
 struct linux_fstatat64_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)];
+	char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_unlinkat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_renameat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)];
 };
 struct linux_linkat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)];
+	char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
 };
 struct linux_symlinkat_args {
-	register_t dummy;
+	char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)];
 };
 struct linux_readlinkat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+	char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)];
 };
 struct linux_fchmodat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)];
 };
 struct linux_faccessat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_pselect6_args {
 	register_t dummy;
--- i386/linux/linux_syscall.h.orig
+++ i386/linux/linux_syscall.h
@@ -2,8 +2,8 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/i386/linux/linux_syscall.h,v 1.85 2007/03/29 02:11:46 julian Exp $
- * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp 
  */
 
 #define	LINUX_SYS_exit	1
--- i386/linux/linux_sysent.c.orig
+++ i386/linux/linux_sysent.c
@@ -2,8 +2,8 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/i386/linux/linux_sysent.c,v 1.92 2007/03/29 02:11:46 julian Exp $
- * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp 
  */
 
 #include <bsm/audit_kevents.h>
@@ -315,18 +315,18 @@
 	{ 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0 },	/* 293 = linux_inotify_rm_watch */
 	{ 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0 },	/* 294 = linux_migrate_pages */
 	{ AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0 },	/* 295 = linux_openat */
-	{ 0, (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
-	{ 0, (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
-	{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
-	{ 0, (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
-	{ 0, (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
-	{ 0, (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
-	{ 0, (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
-	{ 0, (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
-	{ 0, (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
-	{ 0, (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
-	{ 0, (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
-	{ 0, (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
+	{ AS(linux_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
+	{ AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
+	{ AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
+	{ AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
+	{ AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
+	{ AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
+	{ AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
+	{ AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
+	{ AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
+	{ AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
+	{ AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
+	{ AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
 	{ 0, (sy_call_t *)linux_pselect6, AUE_NULL, NULL, 0, 0 },	/* 308 = linux_pselect6 */
 	{ 0, (sy_call_t *)linux_ppoll, AUE_NULL, NULL, 0, 0 },	/* 309 = linux_ppoll */
 	{ 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0 },	/* 310 = linux_unshare */
--- i386/linux/linux_sysvec.c.orig
+++ i386/linux/linux_sysvec.c
@@ -32,6 +32,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/exec.h>
+#include <sys/fcntl.h>
 #include <sys/imgact.h>
 #include <sys/imgact_aout.h>
 #include <sys/imgact_elf.h>
@@ -775,7 +776,7 @@
 	     */
 	    if ((error = exec_shell_imgact(imgp)) == 0) {
 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
-			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
+			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
 		    if (rpath != NULL) {
 			    len = strlen(rpath) + 1;
 
--- i386/linux/syscalls.master.orig
+++ i386/linux/syscalls.master
@@ -473,20 +473,31 @@
 292	AUE_NULL	STD	{ int linux_inotify_add_watch(void); }
 293	AUE_NULL	STD	{ int linux_inotify_rm_watch(void); }
 294	AUE_NULL	STD	{ int linux_migrate_pages(void); }
-295	AUE_OPEN_RWTC	STD	{ int linux_openat(l_int dfd, char *filename, \
+295	AUE_OPEN_RWTC	STD	{ int linux_openat(l_int dfd, const char *filename, \
 					l_int flags, l_int mode); }
-296	AUE_NULL	STD	{ int linux_mkdirat(void); }
-297	AUE_NULL	STD	{ int linux_mknodat(void); }
-298	AUE_NULL	STD	{ int linux_fchownat(void); }
-299	AUE_NULL	STD	{ int linux_futimesat(void); }
-300	AUE_NULL	STD	{ int linux_fstatat64(void); }
-301	AUE_NULL	STD	{ int linux_unlinkat(void); }
-302	AUE_NULL	STD	{ int linux_renameat(void); }
-303	AUE_NULL	STD	{ int linux_linkat(void); }
-304	AUE_NULL	STD	{ int linux_symlinkat(void); }
-305	AUE_NULL	STD	{ int linux_readlinkat(void); }
-306	AUE_NULL	STD	{ int linux_fchmodat(void); }
-307	AUE_NULL	STD	{ int linux_faccessat(void); }
+296	AUE_NULL	STD	{ int linux_mkdirat(l_int dfd, const char *pathname, \
+					l_int mode); }
+297	AUE_NULL	STD	{ int linux_mknodat(l_int dfd, const char *filename, \
+					l_int mode, l_uint dev); }
+298	AUE_NULL	STD	{ int linux_fchownat(l_int dfd, const char *filename, \
+					l_uid16_t uid, l_gid16_t gid, l_int flag); }
+299	AUE_NULL	STD	{ int linux_futimesat(l_int dfd, char *filename, \
+					struct l_timeval *utimes); }
+300	AUE_NULL	STD	{ int linux_fstatat64(l_int dfd, char *pathname, \
+					struct l_stat64 *statbuf, l_int flag); }
+301	AUE_NULL	STD	{ int linux_unlinkat(l_int dfd, const char *pathname, \
+					l_int flag); }
+302	AUE_NULL	STD	{ int linux_renameat(l_int olddfd, const char *oldname, \
+					l_int newdfd, const char *newname); }
+303	AUE_NULL	STD	{ int linux_linkat(l_int olddfd, const char *oldname, \
+					l_int newdfd, const char *newname, l_int flags); }
+304	AUE_NULL	STD	{ int linux_symlinkat(const char *oldname, l_int newdfd, \
+					const char *newname); }
+305	AUE_NULL	STD	{ int linux_readlinkat(l_int dfd, const char *path, \
+					char *buf, l_int bufsiz); }
+306	AUE_NULL	STD	{ int linux_fchmodat(l_int dfd, const char *filename, \
+					l_mode_t mode); }
+307	AUE_NULL	STD	{ int linux_faccessat(l_int dfd, const char *filename, l_int mode); }
 308	AUE_NULL	STD	{ int linux_pselect6(void); }
 309	AUE_NULL	STD	{ int linux_ppoll(void); }
 310	AUE_NULL	STD	{ int linux_unshare(void); }
--- kern/kern_descrip.c.orig
+++ kern/kern_descrip.c
@@ -2003,6 +2003,10 @@
 		FILEDESC_SUNLOCK(fdp);
 		return (EBADF);
 	}
+	if (flags == FEXEC && (fp->f_flag & FREAD) == 0 && (fp->f_flag & FEXEC) == 0) {
+		FILEDESC_SUNLOCK(fdp);
+		return (EBADF);
+	}
 	if (hold) {
 		fhold(fp);
 		FILEDESC_SUNLOCK(fdp);
@@ -2081,6 +2085,29 @@
 }
 #endif
 
+
+/* Gets a vnode if file was opened with either FREAD or FEXEC flag. */
+int
+fgetvp_exec(struct thread *td, int fd, struct vnode **vpp)
+{
+	struct file *fp;
+   	int error;
+
+	*vpp = NULL;	
+
+	if ((error = _fget(td, fd, &fp, FEXEC, 0)) != 0)
+		return (error);
+	if (fp->f_vnode == NULL) {
+		error = EINVAL;
+	} else {
+		*vpp = fp->f_vnode;
+		vref(*vpp);
+	}
+	FILEDESC_SUNLOCK(td->td_proc->p_fd);
+	
+	return (0);	
+}
+
 /*
  * Like fget() but loads the underlying socket, or returns an error if the
  * descriptor does not represent a socket.
--- kern/kern_exec.c.orig
+++ kern/kern_exec.c
@@ -188,6 +188,27 @@
 }
 
 #ifndef _SYS_SYSPROTO_H_
+struct fexecve_args {
+	int	fd;
+	char	**argv;
+	char	**envv;
+}
+#endif
+int
+fexecve(struct thread *td, struct fexecve_args *uap)
+{
+	int error;
+	struct image_args args;
+
+	error = exec_copyin_args(&args, NULL, UIO_SYSSPACE,
+	    uap->argv, uap->envv);
+	args.fd = uap->fd;
+	if (error == 0)
+		error = kern_execve(td, &args, NULL);
+	return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
 struct __mac_execve_args {
 	char	*fname;
 	char	**argv;
@@ -283,7 +304,7 @@
 	struct ucred *newcred = NULL, *oldcred;
 	struct uidinfo *euip;
 	register_t *stack_base;
-	int error, len, i;
+	int error, len = 0, i;
 	struct image_params image_params, *imgp;
 	struct vattr attr;
 	int (*img_first)(struct image_params *);
@@ -293,7 +314,7 @@
 	struct vnode *tracevp = NULL;
 	struct ucred *tracecred = NULL;
 #endif
-	struct vnode *textvp = NULL;
+	struct vnode *textvp = NULL, *binvp = NULL;
 	int credential_changing;
 	int vfslocked;
 	int textset;
@@ -354,17 +375,29 @@
 	 * XXXAUDIT: It would be desirable to also audit the name of the
 	 * interpreter if this is an interpreted binary.
 	 */
-	ndp = &nd;
-	NDINIT(ndp, LOOKUP, ISOPEN | LOCKLEAF | FOLLOW | SAVENAME | MPSAFE |
-	    AUDITVNODE1, UIO_SYSSPACE, args->fname, td);
+	if (args->fname != NULL) {
+   		ndp = &nd;
+		NDINIT(ndp, LOOKUP, ISOPEN | LOCKLEAF | FOLLOW | SAVENAME 
+		    | MPSAFE | AUDITVNODE1, UIO_SYSSPACE, args->fname, td);
+	}
 
 interpret:
-	error = namei(ndp);
-	if (error)
-		goto exec_fail;
+	if (args->fname != NULL) {
+		error = namei(ndp);
+		if (error)
+			goto exec_fail;
 
-	vfslocked = NDHASGIANT(ndp);
-	imgp->vp = ndp->ni_vp;
+		vfslocked = NDHASGIANT(ndp);
+		binvp  = ndp->ni_vp;
+		imgp->vp = binvp;
+	} else {
+	   	error = fgetvp_exec(td, args->fd, &binvp);
+		if (error)
+			goto exec_fail;
+		vfslocked = VFS_LOCK_GIANT(binvp->v_mount);
+		VOP_LOCK(binvp, LK_EXCLUSIVE, td);
+		imgp->vp = binvp;
+	}
 
 	/*
 	 * Check file permissions (also 'opens' file)
@@ -436,12 +469,13 @@
 		 */
 		imgp->vp->v_vflag &= ~VV_TEXT;
 		/* free name buffer and old vnode */
-		NDFREE(ndp, NDF_ONLY_PNBUF);
+		if (args->fname != NULL)
+   			NDFREE(ndp, NDF_ONLY_PNBUF);
 #ifdef MAC
 		interplabel = mac_vnode_label_alloc();
-		mac_copy_vnode_label(ndp->ni_vp->v_label, interplabel);
+		mac_copy_vnode_label(binvp->v_label, interplabel);
 #endif
-		vput(ndp->ni_vp);
+		vput(binvp);
 		vm_object_deallocate(imgp->object);
 		imgp->object = NULL;
 		VFS_UNLOCK_GIANT(vfslocked);
@@ -449,6 +483,7 @@
 		/* set new name to that of the interpreter */
 		NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME | MPSAFE,
 		    UIO_SYSSPACE, imgp->interpreter_name, td);
+		args->fname = imgp->interpreter_name;
 		goto interpret;
 	}
 
@@ -494,7 +529,7 @@
 	vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY, td);
 
 	/* Get a reference to the vnode prior to locking the proc */
-	VREF(ndp->ni_vp);
+	VREF(binvp);
 
 	/*
 	 * For security and other reasons, signal handlers cannot
@@ -520,8 +555,25 @@
 	execsigs(p);
 
 	/* name this process - nameiexec(p, ndp) */
-	len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN);
-	bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len);
+	if (args->fname) {
+   		len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN);
+		bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len);
+	} else {
+		char	*freepath;
+		char	*fullpath = NULL;
+
+		error = vn_fullpath(td, binvp, &fullpath, &freepath);
+		if (error == 0) {
+	   		len = min(strlen(fullpath), MAXCOMLEN);
+	   		bcopy(fullpath, p->p_comm, len);
+			if (freepath)
+				free(freepath, M_TEMP);
+		} else {
+			len = strlen("fexecved process");
+			bcopy("fexecved process", p->p_comm, len);
+		}
+		error = 0;
+	}
 	p->p_comm[len] = 0;
 
 	/*
@@ -650,7 +702,7 @@
 	 * to locking the proc lock.
 	 */
 	textvp = p->p_textvp;
-	p->p_textvp = ndp->ni_vp;
+	p->p_textvp = binvp;
 
 	/*
 	 * Notify others that we exec'd, and clear the P_INEXEC flag
@@ -733,8 +785,8 @@
 		vrele(textvp);
 		VFS_UNLOCK_GIANT(tvfslocked);
 	}
-	if (ndp->ni_vp && error != 0)
-		vrele(ndp->ni_vp);
+	if (binvp && error != 0)
+		vrele(binvp);
 #ifdef KTRACE
 	if (tracevp != NULL) {
 		int tvfslocked;
@@ -763,7 +815,8 @@
 		exec_unmap_first_page(imgp);
 
 	if (imgp->vp != NULL) {
-		NDFREE(ndp, NDF_ONLY_PNBUF);
+		if (args->fname)
+   			NDFREE(ndp, NDF_ONLY_PNBUF);
 		vput(imgp->vp);
 	}
 
@@ -981,11 +1034,14 @@
 	/*
 	 * Copy the file name.
 	 */
-	error = (segflg == UIO_SYSSPACE) ?
-	    copystr(fname, args->fname, PATH_MAX, &length) :
-	    copyinstr(fname, args->fname, PATH_MAX, &length);
-	if (error != 0)
-		goto err_exit;
+	if (fname != NULL) {
+		error = (segflg == UIO_SYSSPACE) ?
+		copystr(fname, args->fname, PATH_MAX, &length) :
+		copyinstr(fname, args->fname, PATH_MAX, &length);
+		if (error != 0)
+			goto err_exit;
+	} else
+		args->fname = NULL;
 
 	/*
 	 * extract arguments first
--- kern/syscalls.master.orig
+++ kern/syscalls.master
@@ -846,5 +846,21 @@
 				    int whence); }
 479	AUE_TRUNCATE	STD	{ int truncate(char *path, off_t length); }
 480	AUE_FTRUNCATE	STD	{ int ftruncate(int fd, off_t length); }
+481	AUE_ACCESS	STD	{ int faccessat(int fd, const char *path, int mode, int flag); }
+482	AUE_CHMOD	STD	{ int fchmodat(int fd, const char *path, mode_t mode, int flag); }
+483	AUE_CHOWN	STD	{ int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag); }
+484	AUE_EXECVE	STD	{ int fexecve(int fd, char **argv, char **envv); }
+485	AUE_STAT	STD	{ int fstatat(int fd, const char *path, struct stat *buf, int flag); }
+486	AUE_UTIMES	STD	{ int futimesat(int fd, const char *path, const struct timeval *times); }
+487	AUE_LINK	STD	{ int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag); }
+488	AUE_MKDIR	STD	{ int mkdirat(int fd, const char *path, mode_t mode); }
+489	AUE_MKFIFO	STD	{ int mkfifoat(int fd, const char *path, mode_t mode); }
+490	AUE_MKNOD	STD	{ int mknodat(int fd, const char *path, mode_t mode, dev_t dev); }
+; XXX: see the comment for open
+491	AUE_OPEN_RWTC	STD	{ int openat(int fd, const char *path, int flag, mode_t mode); }
+492	AUE_READLINK	STD	{ int readlinkat(int fd, const char *path, char *buf, size_t bufsize); }
+493	AUE_RENAME	STD	{ int renameat(int oldfd, const char *old, int newfd, const char *new); }
+494	AUE_SYMLINK	STD	{ int symlinkat(const char *path1, int fd, const char *path2); }
+495	AUE_UNLINK	STD	{ int unlinkat(int fd, const char *path, int flag); }
 ; Please copy any additions and changes to the following compatability tables:
 ; sys/compat/freebsd32/syscalls.master
--- kern/vfs_lookup.c.orig
+++ kern/vfs_lookup.c
@@ -44,6 +44,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/namei.h>
@@ -192,7 +193,14 @@
 	ndp->ni_rootdir = fdp->fd_rdir;
 	ndp->ni_topdir = fdp->fd_jdir;
 
-	dp = fdp->fd_cdir;
+	if (ndp->ni_startdir)
+		dp = ndp->ni_startdir;
+	else {
+		dp = fdp->fd_cdir;
+		/* we might have raced so check it */
+		if ((cnp->cn_flags & ATBADF) && (cnp->cn_pnbuf[0] != '/'))
+			return (EBADF);
+	}
 	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
 	VREF(dp);
 	FILEDESC_SUNLOCK(fdp);
@@ -1000,13 +1008,14 @@
  * the M_TEMP bucket if one is returned.
  */
 int
-kern_alternate_path(struct thread *td, const char *prefix, char *path,
-    enum uio_seg pathseg, char **pathbuf, int create)
+kern_alternate_path(struct thread *td, const char *prefix, const char *path,
+    enum uio_seg pathseg, char **pathbuf, int create, int dirfd)
 {
 	struct nameidata nd, ndroot;
 	char *ptr, *buf, *cp;
 	size_t len, sz;
 	int error;
+	struct vnode *dir_vn;
 
 	buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
 	*pathbuf = buf;
@@ -1039,6 +1048,18 @@
 		goto keeporig;
 	}
 
+	if (dirfd == AT_FDCWD)
+		dir_vn = NULL;
+	else {
+	   	/* 
+		 * we want the original because the "prefix"
+		 * is included in the already opened dirfd
+		 */
+		bcopy(ptr, buf, len);
+		return (0);
+	}
+
+
 	/*
 	 * We know that there is a / somewhere in this pathname.
 	 * Search backwards for it, to find the file's parent dir
@@ -1051,13 +1072,13 @@
 		for (cp = &ptr[len] - 1; *cp != '/'; cp--);
 		*cp = '\0';
 
-		NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td);
+		NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td, dir_vn);
 		error = namei(&nd);
 		*cp = '/';
 		if (error != 0)
 			goto keeporig;
 	} else {
-		NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td);
+		NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td, dir_vn);
 
 		error = namei(&nd);
 		if (error != 0)
--- kern/vfs_syscalls.c.orig
+++ kern/vfs_syscalls.c
@@ -85,8 +85,10 @@
 static int setfflags(struct thread *td, struct vnode *, int);
 static int setutimes(struct thread *td, struct vnode *,
     const struct timespec *, int, int);
+static int kern_get_at(struct thread *td, int dirfd, struct vnode **dvpp);
 static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
     struct thread *td);
+static int kern_absolute_path(const char *path, enum uio_seg pathseg);
 
 /*
  * The module initialization routine for POSIX asynchronous I/O will
@@ -949,14 +951,78 @@
 		int mode;
 	} */ *uap;
 {
+	return kern_open(td, uap->path, UIO_USERSPACE, uap->flags, uap->mode);
+}
 
-	return kern_open(td, uap->path, UIO_USERSPACE, uap->flags, uap->mode);
+#ifndef _SYS_SYSPROTO_H_
+struct openat_args {
+	int	fd;
+	char	*path;
+	int	flag;
+	int	mode;
+};
+#endif
+int
+openat(struct thread *td, struct openat_args *args)
+{
+	return (kern_openat(td, args->fd, args->path, UIO_USERSPACE,
+	   args->flag, args->mode));
 }
 
 int
 kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags,
     int mode)
 {
+	return (kern_openat(td, AT_FDCWD, (const char *)path, pathseg, flags, mode));
+}
+
+static int
+kern_get_at(struct thread *td, int dirfd, struct vnode **dvpp)
+{
+	int error;
+
+	if (dirfd == AT_FDCWD)
+		*dvpp = NULL;
+	else {
+		error = fgetvp(td, dirfd, dvpp);
+		if (error) {
+		   	*dvpp = NULL;
+			return (error);
+		}
+		if ((*dvpp)->v_type != VDIR) {
+			vrele(*dvpp);
+			*dvpp = NULL;
+			return (ENOTDIR);
+		}
+		if (VFS_NEEDSGIANT((*dvpp)->v_mount))
+			mtx_lock(&Giant);
+	}
+
+	return (0);
+}
+
+/* Check whether a path is an absolute path. */
+static int kern_absolute_path(const char *path, enum uio_seg pathseg)
+{
+	int error;
+	char buf[1];
+
+	if (pathseg == UIO_SYSSPACE) {
+		return (path[0] == '/');		
+	} else {
+		error = copyin(path, buf, 1);
+		if (error)
+			return 0;	/* We want to fail. */
+		return (buf[0] == '/');	
+	}
+}
+
+int
+kern_openat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    int flags, int mode)
+{
+	struct nameidata nd;
+	struct vnode *dvp;
 	struct proc *p = td->td_proc;
 	struct filedesc *fdp = p->p_fd;
 	struct file *fp;
@@ -967,23 +1033,32 @@
 	struct file *nfp;
 	int type, indx, error;
 	struct flock lf;
-	struct nameidata nd;
 	int vfslocked;
 
 	AUDIT_ARG(fflags, flags);
 	AUDIT_ARG(mode, mode);
-	if ((flags & O_ACCMODE) == O_ACCMODE)
-		return (EINVAL);
+	/* XXX: audit dirfd */
+
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | FOLLOW | AUDITVNODE1 |
+	    MPSAFE, pathseg, path, td, dvp);
+
+	if ((flags & O_ACCMODE) == O_ACCMODE) {
+		error = EINVAL;
+		goto out;
+	}
 	flags = FFLAGS(flags);
 	error = falloc(td, &nfp, &indx);
 	if (error)
-		return (error);
+		goto out;
 	/* An extra reference on `nfp' has been held for us by falloc(). */
 	fp = nfp;
 	cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
-	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td);
 	td->td_dupfd = -1;		/* XXX check for fdopen */
- 	error = vn_open(&nd, &flags, cmode, fp);
+	error = vn_open(&nd, &flags, cmode, fp);
 	if (error) {
 		/*
 		 * If the vn_open replaced the method vector, something
@@ -993,7 +1068,8 @@
 		if (error == ENXIO && fp->f_ops != &badfileops) {
 			fdrop(fp, td);
 			td->td_retval[0] = indx;
-			return (0);
+			error = 0;
+			goto out;
 		}
 
 		/*
@@ -1007,7 +1083,8 @@
 			dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
 			td->td_retval[0] = indx;
 			fdrop(fp, td);
-			return (0);
+			error = 0;
+			goto out;
 		}
 		/*
 		 * Clean up the descriptor, but only if another thread hadn't
@@ -1018,7 +1095,7 @@
 
 		if (error == ERESTART)
 			error = EINTR;
-		return (error);
+		goto out;
 	}
 	td->td_dupfd = 0;
 	vfslocked = NDHASGIANT(&nd);
@@ -1078,10 +1155,19 @@
 	fdrop(fp, td);
 	td->td_retval[0] = indx;
 	return (0);
+out:
+	if (dvp)
+		vrele(dvp);
+	return (error);
 bad:
 	VFS_UNLOCK_GIANT(vfslocked);
 	fdclose(fdp, fp, indx, td);
 	fdrop(fp, td);
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -1132,11 +1218,32 @@
 	return (kern_mknod(td, uap->path, UIO_USERSPACE, uap->mode, uap->dev));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct mknodat_args {
+	char	*path;
+	mode_t	mode;
+	dev_t	dev;
+};
+#endif
 int
+mknodat(struct thread *td, struct mknodat_args *args)
+{
+	return (kern_mknodat(td, args->fd, args->path, UIO_USERSPACE, args->mode,
+	    args->dev));
+}
+
+int
 kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode,
     int dev)
 {
-	struct vnode *vp;
+	return (kern_mknodat(td, AT_FDCWD, (const char *)path, pathseg, mode, dev));
+}
+
+int
+kern_mknodat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    int mode, int dev)
+{
+	struct vnode *vp, *dvp = NULL;
 	struct mount *mp;
 	struct vattr vattr;
 	int error;
@@ -1164,11 +1271,22 @@
 	if (error)
 		return (error);
 restart:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	NDINIT_AT(&nd, CREATE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    SAVENAME | MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
+	if ((error = namei(&nd)) != 0) {
+		if (dvp)
+			vrele(dvp);
 		return (error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp != NULL) {
@@ -1179,6 +1297,8 @@
 			vput(nd.ni_dvp);
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
+		if (dvp)
+			vrele(dvp);
 		return (EEXIST);
 	} else {
 		VATTR_NULL(&vattr);
@@ -1210,8 +1330,11 @@
 		NDFREE(&nd, NDF_ONLY_PNBUF);
 		vput(nd.ni_dvp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
+		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) {
+			if (dvp)
+				vrele(dvp);
 			return (error);
+		}
 		goto restart;
 	}
 #ifdef MAC
@@ -1230,6 +1353,11 @@
 				vput(nd.ni_vp);
 		}
 	}
+	if (dvp) {
+		int vfslocked1 = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked1);
+	}
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
 	vn_finished_write(mp);
@@ -1258,22 +1386,54 @@
 	return (kern_mkfifo(td, uap->path, UIO_USERSPACE, uap->mode));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct mkfifoat_args {
+	int	fd;
+	char	*path;
+	mode_t	mode;
+};
+#endif
+int
+mkfifoat(struct thread *td, struct mkfifoat_args *args)
+{
+	return (kern_mkfifoat(td, args->fd, args->path, UIO_USERSPACE, args->mode));
+}
+
 int
 kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg, int mode)
 {
+	return (kern_mkfifoat(td, AT_FDCWD, (const char *)path, pathseg, mode));
+}
+
+int
+kern_mkfifoat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    int mode)
+{
 	struct mount *mp;
 	struct vattr vattr;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
+	struct vnode *dvp = NULL;
 
 	AUDIT_ARG(mode, mode);
 restart:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	NDINIT_AT(&nd, CREATE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    SAVENAME | MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
+	if ((error = namei(&nd)) != 0) {
+		if (dvp)
+			vrele(dvp);
 		return (error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	if (nd.ni_vp != NULL) {
 		NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -1283,14 +1443,19 @@
 			vput(nd.ni_dvp);
 		vrele(nd.ni_vp);
 		VFS_UNLOCK_GIANT(vfslocked);
+		if (dvp)
+			vrele(dvp);
 		return (EEXIST);
 	}
 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
 		NDFREE(&nd, NDF_ONLY_PNBUF);
 		vput(nd.ni_dvp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
+		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) {
+			if (dvp)
+				vrele(dvp);
 			return (error);
+	}
 		goto restart;
 	}
 	VATTR_NULL(&vattr);
@@ -1311,6 +1476,11 @@
 #ifdef MAC
 out:
 #endif
+	if (dvp) {
+		int vfslocked1 = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked1);
+	}
 	vput(nd.ni_dvp);
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
@@ -1341,6 +1511,29 @@
 	return (error);
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct linkat_args {
+   	int	fd1;
+	char	*path1;
+	int	fd2;
+	char	*path2;
+	int	flag;
+};
+#endif
+int
+linkat(struct thread *td, struct linkat_args *args)
+{
+   	if (args->flag & ~AT_SYMLINK_FOLLOW)
+		return (EINVAL);
+
+	if (args->flag & AT_SYMLINK_FOLLOW)
+		return (kern_linkat(td, args->fd1, args->fd2, args->path1,
+		    args->path2, UIO_USERSPACE, FOLLOW));
+	else
+		return (kern_linkat(td, args->fd1, args->fd2, args->path1,
+		    args->path2, UIO_USERSPACE, 0));
+}
+
 static int hardlink_check_uid = 0;
 SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_uid, CTLFLAG_RW,
     &hardlink_check_uid, 0,
@@ -1383,62 +1576,101 @@
 int
 kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
 {
+	return (kern_linkat(td, AT_FDCWD, AT_FDCWD, (const char *)path,
+	    (const char *)link, segflg, FOLLOW));
+}
+
+int
+kern_linkat(struct thread *td, int fd1, int fd2, const char *path1, const char *path2,
+    enum uio_seg segflg, int follow)
+{
+	struct nameidata ndp, ndl;
+	struct vnode *pdvp = NULL, *ldvp = NULL;
 	struct vnode *vp;
 	struct mount *mp;
-	struct nameidata nd;
 	int vfslocked;
 	int lvfslocked;
 	int error;
 
+	error = kern_get_at(td, fd1, &pdvp);
+	if (error && !kern_absolute_path(path1, segflg))
+		return (error);
+
+	NDINIT_AT(&ndp, LOOKUP, ((error) ? ATBADF : 0) | follow | MPSAFE |
+	    AUDITVNODE1, segflg, path1, td, pdvp);
+
+	error = kern_get_at(td, fd2, &ldvp);
+	if (error && !kern_absolute_path(path2, segflg)) {
+		if (pdvp) {
+			vfslocked = VFS_NEEDSGIANT(pdvp->v_mount); 
+			vrele(pdvp);
+			VFS_UNLOCK_GIANT(vfslocked);
+		}
+		return (error);
+	}
+
+	NDINIT_AT(&ndl, CREATE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    SAVENAME | MPSAFE | AUDITVNODE1, segflg, path2, td, ldvp);
+
 	bwillwrite();
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td);
-	if ((error = namei(&nd)) != 0)
-		return (error);
-	vfslocked = NDHASGIANT(&nd);
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vp = nd.ni_vp;
+	if ((error = namei(&ndp)) != 0)
+		goto out;
+	vfslocked = NDHASGIANT(&ndp);
+	NDFREE(&ndp, NDF_ONLY_PNBUF);
+	vp = ndp.ni_vp;
 	if (vp->v_type == VDIR) {
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		return (EPERM);		/* POSIX */
+		error = EPERM;		/* POSIX */
+		goto out;
 	}
 	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		return (error);
+		goto out;
 	}
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE2,
-	    segflg, link, td);
-	if ((error = namei(&nd)) == 0) {
-		lvfslocked = NDHASGIANT(&nd);
-		if (nd.ni_vp != NULL) {
-			if (nd.ni_dvp == nd.ni_vp)
-				vrele(nd.ni_dvp);
+	if ((error = namei(&ndl)) == 0) {
+		lvfslocked = NDHASGIANT(&ndl);
+		if (ndl.ni_vp != NULL) {
+			if (ndl.ni_dvp == ndl.ni_vp)
+				vrele(ndl.ni_dvp);
 			else
-				vput(nd.ni_dvp);
-			vrele(nd.ni_vp);
+				vput(ndl.ni_dvp);
+			vrele(ndl.ni_vp);
 			error = EEXIST;
 		} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
 		    == 0) {
-			VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
+			VOP_LEASE(ndl.ni_dvp, td, td->td_ucred, LEASE_WRITE);
 			VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
 			error = can_hardlink(vp, td, td->td_ucred);
 			if (error == 0)
 #ifdef MAC
 				error = mac_check_vnode_link(td->td_ucred,
-				    nd.ni_dvp, vp, &nd.ni_cnd);
+				    ndl.ni_dvp, vp, &ndl.ni_cnd);
 			if (error == 0)
 #endif
-				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+				error = VOP_LINK(ndl.ni_dvp, vp, &ndl.ni_cnd);
 			VOP_UNLOCK(vp, 0, td);
-			vput(nd.ni_dvp);
+			vput(ndl.ni_dvp);
 		}
-		NDFREE(&nd, NDF_ONLY_PNBUF);
+		NDFREE(&ndl, NDF_ONLY_PNBUF);
 		VFS_UNLOCK_GIANT(lvfslocked);
 	}
 	vrele(vp);
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
+
+out:
+	if (pdvp) {
+		vfslocked = VFS_NEEDSGIANT(pdvp->v_mount); 
+		vrele(pdvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	if (ldvp) {
+		vfslocked = VFS_NEEDSGIANT(ldvp->v_mount); 
+		vrele(ldvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -1463,28 +1695,58 @@
 	return (kern_symlink(td, uap->path, uap->link, UIO_USERSPACE));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct symlinkat_args {
+	char	*path;
+	int	fd;
+	char	*path2;
+};
+#endif
 int
+symlinkat(struct thread *td, struct symlinkat_args *args)
+{
+	return (kern_symlinkat(td, args->path1, args->fd, args->path2, UIO_USERSPACE));
+}
+
+int
 kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg)
 {
+	return (kern_symlinkat(td, (const char *)path, AT_FDCWD, (const char *)link,
+	    segflg));
+}
+
+int
+kern_symlinkat(struct thread *td, const char *path1, int fd, const char *path2,
+    enum uio_seg segflg)
+{
 	struct mount *mp;
 	struct vattr vattr;
 	char *syspath;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
+	struct vnode *dvp = NULL;
 
 	if (segflg == UIO_SYSSPACE) {
-		syspath = path;
+		syspath = __DECONST(char *, path1);
 	} else {
 		syspath = uma_zalloc(namei_zone, M_WAITOK);
-		if ((error = copyinstr(path, syspath, MAXPATHLEN, NULL)) != 0)
+		if ((error = copyinstr(path1, syspath, MAXPATHLEN, NULL)) != 0)
 			goto out;
 	}
 	AUDIT_ARG(text, syspath);
 restart:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path2, segflg))
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    segflg, link, td);
+	NDINIT_AT(&nd, CREATE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    SAVENAME | MPSAFE | AUDITVNODE1, segflg, path2, td, dvp);
 	if ((error = namei(&nd)) != 0)
 		goto out;
 	vfslocked = NDHASGIANT(&nd);
@@ -1530,6 +1792,11 @@
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
 out:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	if (segflg != UIO_SYSSPACE)
 		uma_zfree(namei_zone, syspath);
 	return (error);
@@ -1608,21 +1875,57 @@
 	return (error);
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct unlinkat_args {
+	int	fd;
+	char	*path;
+	int	flag;
+};
+#endif
+int
+unlinkat(struct thread *td, struct unlinkat_args *args)
+{
+	if (args->flag & ~AT_REMOVEDIR)
+		return (EINVAL);
+
+	if (args->flag & AT_REMOVEDIR)
+		return (kern_rmdirat(td, args->fd, args->path, UIO_USERSPACE));
+	else
+		return (kern_unlinkat(td, args->fd, args->path, UIO_USERSPACE));
+}
+
 int
 kern_unlink(struct thread *td, char *path, enum uio_seg pathseg)
 {
+	return (kern_unlinkat(td, AT_FDCWD, (const char *)path, pathseg));
+}
+
+int
+kern_unlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg)
+{
 	struct mount *mp;
-	struct vnode *vp;
+	struct vnode *vp, *dvp = NULL;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
 
 restart:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	NDINIT_AT(&nd, DELETE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
+	if ((error = namei(&nd)) != 0) {
+		if (dvp)
+			vrele(dvp);		
 		return (error == EINVAL ? EPERM : error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp->v_type == VDIR)
@@ -1646,8 +1949,11 @@
 				vput(vp);
 			VFS_UNLOCK_GIANT(vfslocked);
 			if ((error = vn_start_write(NULL, &mp,
-			    V_XSLEEP | PCATCH)) != 0)
+			    V_XSLEEP | PCATCH)) != 0) {
+				if (dvp)
+					vrele(dvp);
 				return (error);
+			}
 			goto restart;
 		}
 #ifdef MAC
@@ -1665,6 +1971,11 @@
 	}
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
+	if (dvp) {
+		int vfslocked1 = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked1);
+	}
 	if (vp == nd.ni_dvp)
 		vrele(vp);
 	else
@@ -1861,15 +2172,46 @@
 	return (kern_access(td, uap->path, UIO_USERSPACE, uap->flags));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct faccessat_args {
+	int	dirfd;
+	char	*path;
+	int	mode;
+	int	flag;
+}
+#endif
+int faccessat(struct thread *td, struct faccessat_args *args)
+{
+	if (args->flag & ~AT_EACCESS)
+		return (EINVAL);
+	/* XXX: what about mode? */
+	return (kern_accessat(td, args->fd, args->path, UIO_USERSPACE, args->flag));
+}
+
 int
 kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags)
 {
+	return (kern_accessat(td, AT_FDCWD, (const char *)path, pathseg, flags));
+}
+
+int
+kern_accessat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    int flags)
+{
+	struct nameidata nd;
+	struct vnode *dvp;
 	struct ucred *cred, *tmpcred;
-	register struct vnode *vp;
-	struct nameidata nd;
+	struct vnode *vp;
 	int vfslocked;
 	int error;
 
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | FOLLOW | LOCKLEAF |
+	    MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
+
 	/*
 	 * Create and modify a temporary credential instead of one that
 	 * is potentially shared.  This could also mess up socket
@@ -1877,13 +2219,16 @@
 	 */
 	cred = td->td_ucred;
 	tmpcred = crdup(cred);
-	tmpcred->cr_uid = cred->cr_ruid;
-	tmpcred->cr_groups[0] = cred->cr_rgid;
+	if (flags & AT_EACCESS) {
+		tmpcred->cr_uid = cred->cr_uid;
+		tmpcred->cr_groups[0] = cred->cr_groups[0];
+	} else {
+		tmpcred->cr_uid = cred->cr_ruid;
+		tmpcred->cr_groups[0] = cred->cr_rgid;
+	}
 	td->td_ucred = tmpcred;
-	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		goto out1;
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 
@@ -1891,9 +2236,14 @@
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
-out1:
+out:
 	td->td_ucred = cred;
 	crfree(tmpcred);
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -2054,18 +2404,50 @@
 	return (error);
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct fstatat_args {
+	int	fd;
+	char	*path;
+	struct stat	*buf;
+	int	flag;
+}
+#endif
+int
+fstatat(struct thread *td, struct fstatat_args *args)
+{
+	if (args->flag & ~AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+
+	if (args->flag & AT_SYMLINK_NOFOLLOW)
+		return (kern_lstatat(td, args->fd, args->path, UIO_USERSPACE, args->buf));
+	else
+		return (kern_statat(td, args->fd, args->path, UIO_USERSPACE, args->buf));
+}
+
 int
 kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
 {
+	return (kern_statat(td, AT_FDCWD, (const char *)path, pathseg, sbp));
+}
+
+int
+kern_statat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    struct stat *sbp)
+{
 	struct nameidata nd;
+	struct vnode *dvp;
 	struct stat sb;
 	int error, vfslocked;
 
-	NDINIT(&nd, LOOKUP,
-	    FOLLOW | LOCKSHARED | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | FOLLOW | LOCKSHARED |
+	    LOCKLEAF | AUDITVNODE1 | MPSAFE, pathseg, path, td, dvp);
+
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -2073,10 +2455,15 @@
 	VFS_UNLOCK_GIANT(vfslocked);
 	if (mtx_owned(&Giant))
 		printf("stat(%d): %s\n", vfslocked, path);
-	if (error)
-		return (error);
-	*sbp = sb;
-	return (0);
+	if (error == 0)
+		*sbp = sb;
+out:	
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	return (error);
 }
 
 /*
@@ -2108,26 +2495,42 @@
 int
 kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
 {
+	return (kern_lstatat(td, AT_FDCWD, (const char *)path, pathseg, sbp));
+}
+
+int
+kern_lstatat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    struct stat *sbp)
+{
+	struct nameidata nd;
+	struct vnode *dvp;
 	struct vnode *vp;
 	struct stat sb;
-	struct nameidata nd;
 	int error, vfslocked;
 
-	NDINIT(&nd, LOOKUP,
-	    NOFOLLOW | LOCKLEAF | LOCKSHARED | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | NOFOLLOW | LOCKLEAF |
+	    LOCKSHARED | MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
-	if (error)
-		return (error);
-	*sbp = sb;
-	return (0);
+	if (error == 0)
+		*sbp = sb;
+out:	
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	return (error);
 }
 
 /*
@@ -2279,22 +2682,49 @@
 	return (kern_readlink(td, uap->path, UIO_USERSPACE, uap->buf,
 	    UIO_USERSPACE, uap->count));
 }
+#ifndef _SYS_SYSPROTO_H_
+struct readlinkat_args {
+	int	fd;
+	char	*path;
+	char	*buf;
+	size_t	bufsize;
+};
+#endif
+int
+readlinkat(struct thread *td, struct readlinkat_args *args)
+{
+	return (kern_readlinkat(td, args->fd, args->path, UIO_USERSPACE,
+	    args->buf, UIO_USERSPACE, args->bufsize));
+}
 
 int
 kern_readlink(struct thread *td, char *path, enum uio_seg pathseg, char *buf,
     enum uio_seg bufseg, int count)
 {
-	register struct vnode *vp;
+	return (kern_readlinkat(td, AT_FDCWD, (const char *)path, pathseg, buf,
+	    bufseg, count));
+}
+
+int
+kern_readlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    char *buf, enum uio_seg bufseg, int count)
+{
+	struct nameidata nd;
+	struct vnode *dvp;
+	struct vnode *vp;
 	struct iovec aiov;
 	struct uio auio;
-	int error;
-	struct nameidata nd;
-	int vfslocked;
+	int error, vfslocked;
+
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | NOFOLLOW | LOCKLEAF |
+	    MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
 
-	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
@@ -2303,7 +2733,7 @@
 	if (error) {
 		vput(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		return (error);
+		goto out;
 	}
 #endif
 	if (vp->v_type != VLNK)
@@ -2323,6 +2753,12 @@
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
 	td->td_retval[0] = count - auio.uio_resid;
+out:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -2467,6 +2903,7 @@
 }
 
 /*
+ *
  * Common implementation code for chmod(), lchmod() and fchmod().
  */
 static int
@@ -2516,22 +2953,62 @@
 	return (kern_chmod(td, uap->path, UIO_USERSPACE, uap->mode));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct fchmodat_args {
+	int	dirfd;
+	char	*path;
+	mode_t	mode;
+	int	flag;
+}
+#endif
 int
+fchmodat(struct thread *td, struct fchmodat_args *args)
+{
+	if (args->flag & ~AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+
+	if (args->flag & AT_SYMLINK_NOFOLLOW)
+		return (kern_lchmodat(td, args->fd, args->path, UIO_USERSPACE,
+		    args->mode));
+	else
+		return (kern_chmodat(td, args->fd, args->path, UIO_USERSPACE,
+		    args->mode));
+}
+
+int
 kern_chmod(struct thread *td, char *path, enum uio_seg pathseg, int mode)
 {
-	int error;
+	return (kern_chmodat(td, AT_FDCWD, (const char *)path, pathseg, mode));
+}
+
+int
+kern_chmodat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    mode_t mode)
+{
 	struct nameidata nd;
-	int vfslocked;
+	struct vnode *dvp;
+	int error, vfslocked;
+
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | FOLLOW | MPSAFE |
+	    AUDITVNODE1, pathseg, path, td, dvp);
 
-	AUDIT_ARG(mode, mode);
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setfmode(td, nd.ni_vp, mode);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:	
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -2552,20 +3029,39 @@
 		int mode;
 	} */ *uap;
 {
+	return (kern_lchmodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode));
+}
+
+
+int
+kern_lchmodat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    mode_t mode)
+{
 	int error;
 	struct nameidata nd;
 	int vfslocked;
+	struct vnode *dvp;
 
-	AUDIT_ARG(mode, (mode_t)uap->mode);
-	NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, UIO_USERSPACE,
-	    uap->path, td);
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	AUDIT_ARG(mode, mode);
+	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg,
+	    path, td, dvp);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
-	error = setfmode(td, nd.ni_vp, uap->mode);
+	error = setfmode(td, nd.ni_vp, mode);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+
 	return (error);
 }
 
@@ -2661,23 +3157,57 @@
 	return (kern_chown(td, uap->path, UIO_USERSPACE, uap->uid, uap->gid));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+#endif
 int
+fchownat(struct thread *td, struct fchownat_args *args)
+{
+	if (args->flag & ~AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+
+	if (args->flag & AT_SYMLINK_NOFOLLOW)
+		return (kern_lchownat(td, args->fd, args->path, UIO_USERSPACE,
+		    args->uid, args->gid));
+	else
+		return (kern_chownat(td, args->fd, args->path, UIO_USERSPACE,
+		    args->uid, args->gid));
+}
+
+int
 kern_chown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
     int gid)
 {
-	int error;
+	return (kern_chownat(td, AT_FDCWD, (const char *)path, pathseg, uid, gid));
+}
+
+int
+kern_chownat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    int uid, int gid)
+{
 	struct nameidata nd;
-	int vfslocked;
+	struct vnode *dvp;
+	int error, vfslocked;
+
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | FOLLOW | MPSAFE |
+	    AUDITVNODE1, pathseg, path, td, dvp);
 
-	AUDIT_ARG(owner, uid, gid);
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setfown(td, nd.ni_vp, uid, gid);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:	
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -2708,19 +3238,37 @@
 kern_lchown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
     int gid)
 {
-	int error;
+	return (kern_lchownat(td, AT_FDCWD, (const char *)path, pathseg, uid, gid));
+}
+
+int
+kern_lchownat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    int uid, int gid)
+{
 	struct nameidata nd;
-	int vfslocked;
+	struct vnode *dvp;
+	int error, vfslocked;
+
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | NOFOLLOW | MPSAFE |
+	    AUDITVNODE1, pathseg, path, td, dvp);
 
-	AUDIT_ARG(owner, uid, gid);
-	NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setfown(td, nd.ni_vp, uid, gid);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:	
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -2863,25 +3411,54 @@
 	    UIO_USERSPACE));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+#endif
+int
+futimesat(struct thread *td, struct futimesat_args *args)
+{
+	return (kern_utimesat(td, args->fd, args->path, UIO_USERSPACE,
+	    args->times, UIO_USERSPACE));
+}
+
 int
 kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
     struct timeval *tptr, enum uio_seg tptrseg)
 {
+	return (kern_utimesat(td, AT_FDCWD, (const char *)path, pathseg,
+	    (const struct timeval *)tptr, tptrseg));
+}
+
+int
+kern_utimesat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+    const struct timeval *tptr, enum uio_seg tptrseg)
+{
+	struct nameidata nd;
+	struct vnode *dvp;
 	struct timespec ts[2];
-	int error;
-	struct nameidata nd;
-	int vfslocked;
+	int error, vfslocked;
+
+   	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, ((error) ? ATBADF : 0) | FOLLOW | MPSAFE |
+	    AUDITVNODE1, pathseg, path, td, dvp);
 
 	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
-		return (error);
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
+		goto out;
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
 	return (error);
 }
 
@@ -3250,26 +3827,68 @@
 	return (kern_rename(td, uap->from, uap->to, UIO_USERSPACE));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct renameat_args {
+	int	oldfd;
+	char	*old;
+	int	newfd;
+	char	*new;
+};
+#endif
 int
+renameat(struct thread *td, struct renameat_args *args)
+{
+	return (kern_renameat(td, args->oldfd, args->old, args->newfd, args->new,
+	    UIO_USERSPACE));
+}
+
+int
 kern_rename(struct thread *td, char *from, char *to, enum uio_seg pathseg)
 {
+	return (kern_renameat(td, AT_FDCWD, (const char *)from, AT_FDCWD,
+	    (const char *)to, pathseg));
+}
+
+int
+kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
+    const char *new, enum uio_seg pathseg)
+{
+	struct nameidata fromnd, tond;
+	struct vnode *frdvp = NULL, *todvp = NULL;
 	struct mount *mp = NULL;
 	struct vnode *tvp, *fvp, *tdvp;
-	struct nameidata fromnd, tond;
 	int tvfslocked;
 	int fvfslocked;
 	int error;
 
-	bwillwrite();
+	error = kern_get_at(td, oldfd, &frdvp);
+	if (error && !kern_absolute_path(old, pathseg))
+		return (error);
+
+	error = kern_get_at(td, newfd, &todvp);
+	if (error && !kern_absolute_path(new, pathseg)) {
+		if (frdvp) {
+			fvfslocked = VFS_NEEDSGIANT(frdvp->v_mount); 
+			vrele(frdvp);
+			VFS_UNLOCK_GIANT(fvfslocked);
+		}
+		return (error);
+	}
+
 #ifdef MAC
-	NDINIT(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | MPSAFE |
-	    AUDITVNODE1, pathseg, from, td);
+	NDINIT_AT(&fromnd, DELETE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    LOCKLEAF | SAVESTART | MPSAFE | AUDITVNODE1, pathseg, old, td, frdvp);
 #else
-	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART | MPSAFE |
-	    AUDITVNODE1, pathseg, from, td);
+	NDINIT_AT(&fromnd, DELETE, ((error) ? ATBADF : 0) | WANTPARENT |
+	    SAVESTART | MPSAFE | AUDITVNODE1, pathseg, old, td, frdvp);
 #endif
+	NDINIT_AT(&tond, RENAME, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    LOCKLEAF | NOCACHE | SAVESTART | MPSAFE | AUDITVNODE2,
+	    pathseg, new, td, todvp);
+
+	bwillwrite();
 	if ((error = namei(&fromnd)) != 0)
-		return (error);
+		goto out2;
 	fvfslocked = NDHASGIANT(&fromnd);
 	tvfslocked = 0;
 #ifdef MAC
@@ -3288,8 +3907,6 @@
 		vrele(fvp);
 		goto out1;
 	}
-	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
-	    MPSAFE | AUDITVNODE2, pathseg, to, td);
 	if (fromnd.ni_vp->v_type == VDIR)
 		tond.ni_cnd.cn_flags |= WILLBEDIR;
 	if ((error = namei(&tond)) != 0) {
@@ -3361,6 +3978,17 @@
 	VFS_UNLOCK_GIANT(tvfslocked);
 	if (error == -1)
 		return (0);
+out2:
+	if (frdvp) {
+		fvfslocked = VFS_NEEDSGIANT(frdvp->v_mount); 
+		vrele(frdvp);
+		VFS_UNLOCK_GIANT(fvfslocked);
+	}
+	if (todvp) {
+		tvfslocked = VFS_NEEDSGIANT(todvp->v_mount); 
+		vrele(todvp);
+		VFS_UNLOCK_GIANT(tvfslocked);
+	}
 	return (error);
 }
 
@@ -3385,11 +4013,31 @@
 	return (kern_mkdir(td, uap->path, UIO_USERSPACE, uap->mode));
 }
 
+#ifndef _SYS_SYSPROTO_H_
+struct mkdirat_args {
+	int	fd;
+	char	*path;
+	mode_t	mode;
+};
+#endif
+int
+mkdirat(struct thread *td, struct mkdirat_args *args)
+{
+	return (kern_mkdirat(td, args->fd, args->path, UIO_USERSPACE, args->mode));
+}
+
 int
 kern_mkdir(struct thread *td, char *path, enum uio_seg segflg, int mode)
 {
+	return (kern_mkdirat(td, AT_FDCWD, (const char *)path, segflg, mode));
+}
+
+int
+kern_mkdirat(struct thread *td, int fd, const char *path, enum uio_seg segflg,
+    int mode)
+{
 	struct mount *mp;
-	struct vnode *vp;
+	struct vnode *vp, *dvp = NULL;
 	struct vattr vattr;
 	int error;
 	struct nameidata nd;
@@ -3397,12 +4045,23 @@
 
 	AUDIT_ARG(mode, mode);
 restart:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, segflg))
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    segflg, path, td);
+	NDINIT_AT(&nd, CREATE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    SAVENAME | MPSAFE | AUDITVNODE1, segflg, path, td, dvp);
 	nd.ni_cnd.cn_flags |= WILLBEDIR;
-	if ((error = namei(&nd)) != 0)
+	if ((error = namei(&nd)) != 0) {
+		if (dvp)
+			vrele(dvp);
 		return (error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp != NULL) {
@@ -3418,14 +4077,19 @@
 			vput(nd.ni_dvp);
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
+		if (dvp)
+			vrele(dvp);
 		return (EEXIST);
 	}
 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
 		NDFREE(&nd, NDF_ONLY_PNBUF);
 		vput(nd.ni_dvp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
+		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) {
+			if (dvp)
+				vrele(dvp);
 			return (error);
+		}
 		goto restart;
 	}
 	VATTR_NULL(&vattr);
@@ -3444,6 +4108,11 @@
 #ifdef MAC
 out:
 #endif
+	if (dvp) {
+		int vfslocked1 = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked1);
+	}
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
 	if (!error)
@@ -3475,16 +4144,30 @@
 int
 kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg)
 {
+	return (kern_rmdirat(td, AT_FDCWD, (const char *)path, pathseg));
+}
+
+int
+kern_rmdirat(struct thread *td, int fd, const char *path, enum uio_seg pathseg)
+{
 	struct mount *mp;
-	struct vnode *vp;
+	struct vnode *vp, *dvp = NULL;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
 
 restart:
+	if (dvp) {
+		vfslocked = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked);
+	}
+	error = kern_get_at(td, fd, &dvp);
+	if (error && !kern_absolute_path(path, pathseg))
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
+	NDINIT_AT(&nd, DELETE, ((error) ? ATBADF : 0) | LOCKPARENT |
+	    LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg, path, td, dvp);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	vfslocked = NDHASGIANT(&nd);
@@ -3532,6 +4215,11 @@
 out:
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(vp);
+	if (dvp) {
+		int vfslocked1 = VFS_NEEDSGIANT(dvp->v_mount); 
+		vrele(dvp);
+		VFS_UNLOCK_GIANT(vfslocked1);
+	}
 	if (nd.ni_dvp == vp)
 		vrele(nd.ni_dvp);
 	else
--- sys/fcntl.h.orig
+++ sys/fcntl.h
@@ -96,15 +96,24 @@
 #define	O_FSYNC		0x0080		/* synchronous writes */
 #endif
 #define	O_SYNC		0x0080		/* POSIX synonym for O_FSYNC */
-#if __BSD_VISIBLE
 #define	O_NOFOLLOW	0x0100		/* don't follow symlinks */
-#endif
 #define	O_CREAT		0x0200		/* create if nonexistent */
 #define	O_TRUNC		0x0400		/* truncate to zero length */
 #define	O_EXCL		0x0800		/* error if already exists */
 #ifdef _KERNEL
 #define	FHASLOCK	0x4000		/* descriptor holds advisory lock */
 #endif
+#define	O_EXEC		0x8000		/* open for execute only */
+#define	FEXEC		0x8000
+/* Defined by POSIX Extended API ... TODO: number of the spec */
+#define	AT_FDCWD		-100	/* Use the current working directory
+					   to determine the target of relative
+					   file paths.
+					 */
+#define	AT_EACCESS		0x100	/* Check access using effective user and group ID */
+#define	AT_SYMLINK_NOFOLLOW	0x200   /* Do not follow symbolic links */
+#define	AT_SYMLINK_FOLLOW	0x400	/* Follow symbolic link */
+#define	AT_REMOVEDIR		0x800	/* Remove directory instead of file */
 
 /* Defined by POSIX 1003.1; BSD default, but must be distinct from O_RDONLY. */
 #define	O_NOCTTY	0x8000		/* don't assign controlling terminal */
@@ -114,6 +123,9 @@
 #define O_DIRECT	0x00010000
 #endif
 
+/* Defined by POSIX Extended API ... TODO: number of the spec */
+#define	O_DIRECTORY	0x00020000	/* Fail if not directory */
+
 /*
  * XXX missing O_DSYNC, O_RSYNC.
  */
@@ -124,7 +136,7 @@
 #define	OFLAGS(fflags)	((fflags) - 1)
 
 /* bits to save after open */
-#define	FMASK		(FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK|O_DIRECT)
+#define	FMASK		(FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK|O_DIRECT|FEXEC)
 /* bits settable by fcntl(F_SETFL, ...) */
 #define	FCNTLFLAGS	(FAPPEND|FASYNC|FFSYNC|FNONBLOCK|FPOSIXSHM|O_DIRECT)
 #endif
@@ -220,6 +232,7 @@
 int	open(const char *, int, ...);
 int	creat(const char *, mode_t);
 int	fcntl(int, int, ...);
+int	openat(int, const char *, int, ...);
 #if __BSD_VISIBLE
 int	flock(int, int);
 #endif
--- sys/file.h.orig
+++ sys/file.h
@@ -205,6 +205,7 @@
 int fgetvp(struct thread *td, int fd, struct vnode **vpp);
 int fgetvp_read(struct thread *td, int fd, struct vnode **vpp);
 int fgetvp_write(struct thread *td, int fd, struct vnode **vpp);
+int fgetvp_exec(struct thread *td, int fd, struct vnode **vpp);
 
 int fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp);
 void fputsock(struct socket *sp);
--- sys/imgact.h.orig
+++ sys/imgact.h
@@ -45,6 +45,7 @@
 	int stringspace;	/* space left in arg & env buffer */
 	int argc;		/* count of argument strings */
 	int envc;		/* count of environment strings */
+	int fd;			/* file descriptor of the executable */
 };
 
 struct image_params {
--- sys/namei.h.orig
+++ sys/namei.h
@@ -66,7 +66,10 @@
 	/*
 	 * Arguments to lookup.
 	 */
-	struct	vnode *ni_startdir;	/* starting directory */
+	struct	vnode *ni_startdir;	/* 
+					 * starting directory, also used for 
+					 * rename and *at functions 
+					 */
 	struct	vnode *ni_rootdir;	/* logical root directory */
 	struct	vnode *ni_topdir;	/* logical top directory */
 	/*
@@ -106,8 +109,9 @@
 #define	NOCACHE		0x0020	/* name must not be left in cache */
 #define	FOLLOW		0x0040	/* follow symbolic links */
 #define	LOCKSHARED	0x0100	/* Shared lock leaf */
+#define	ATBADF		0x0200	/* called from *at context with invalid dirfd */
 #define	NOFOLLOW	0x0000	/* do not follow symbolic links (pseudo) */
-#define	MODMASK		0x01fc	/* mask of operational modifiers */
+#define	MODMASK		0x03fc	/* mask of operational modifiers */
 /*
  * Namei parameter descriptors.
  *
@@ -148,20 +152,23 @@
 /*
  * Initialization of a nameidata structure.
  */
-static void NDINIT(struct nameidata *, u_long, u_long, enum uio_seg,
-	    const char *, struct thread *);
+#define	NDINIT(ndp, op, flags, segflg, namep, td)	\
+		NDINIT_AT(ndp, op, flags, segflg, namep, td, NULL)
+
 static __inline void
-NDINIT(struct nameidata *ndp,
+NDINIT_AT(struct nameidata *ndp,
 	u_long op, u_long flags,
 	enum uio_seg segflg,
 	const char *namep,
-	struct thread *td)
+	struct thread *td,
+	struct vnode *dvp)
 {
 	ndp->ni_cnd.cn_nameiop = op;
 	ndp->ni_cnd.cn_flags = flags;
 	ndp->ni_segflg = segflg;
 	ndp->ni_dirp = namep;
 	ndp->ni_cnd.cn_thread = td;
+	ndp->ni_startdir = dvp;
 }
 
 #define NDF_NO_DVP_RELE		0x00000001
--- sys/stat.h.orig
+++ sys/stat.h
@@ -338,6 +338,10 @@
 #endif
 int	stat(const char * __restrict, struct stat * __restrict);
 mode_t	umask(mode_t);
+int	fstatat(int, const char *, struct stat *, int);
+int	mkdirat(int, const char *, mode_t);
+int	mkfifoat(int, const char *, mode_t);
+int	mknodat(int, const char *, mode_t, dev_t);
 __END_DECLS
 #endif /* !_KERNEL */
 
--- sys/syscallsubr.h.orig
+++ sys/syscallsubr.h
@@ -56,16 +56,24 @@
 	    socklen_t *namelen, struct file **fp);
 int	kern_access(struct thread *td, char *path, enum uio_seg pathseg,
 	    int flags);
+int	kern_accessat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, int flags);
 int	kern_adjtime(struct thread *td, struct timeval *delta,
 	    struct timeval *olddelta);
-int	kern_alternate_path(struct thread *td, const char *prefix, char *path,
-	    enum uio_seg pathseg, char **pathbuf, int create);
+int	kern_alternate_path(struct thread *td, const char *prefix, const char *path,
+	    enum uio_seg pathseg, char **pathbuf, int create, int dirfd);
 int	kern_bind(struct thread *td, int fd, struct sockaddr *sa);
 int	kern_chdir(struct thread *td, char *path, enum uio_seg pathseg);
 int	kern_chmod(struct thread *td, char *path, enum uio_seg pathseg,
 	    int mode);
+int	kern_chmodat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, mode_t mode);
 int	kern_chown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
 	    int gid);
+int	kern_chownat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, int uid, int gid);
+int	kern_lchmodat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, mode_t mode);
 int	kern_clock_getres(struct thread *td, clockid_t clock_id,
 	    struct timespec *ts);
 int	kern_clock_gettime(struct thread *td, clockid_t clock_id,
@@ -102,18 +110,30 @@
 int	kern_kldunload(struct thread *td, int fileid, int flags);
 int	kern_lchown(struct thread *td, char *path, enum uio_seg pathseg,
 	    int uid, int gid);
+int	kern_lchownat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, int uid, int gid);
 int	kern_link(struct thread *td, char *path, char *link,
 	    enum uio_seg segflg);
+int	kern_linkat(struct thread *td, int fd1, int fd2, const char *path1,
+	    const char *path2, enum uio_seg segflg, int follow);
 int	kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct stat *sbp);
+int	kern_lstatat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, struct stat *sbp);
 int	kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct timeval *tptr, enum uio_seg tptrseg);
 int	kern_mkdir(struct thread *td, char *path, enum uio_seg segflg,
 	    int mode);
+int	kern_mkdirat(struct thread *td, int fd, const char *path,
+	    enum uio_seg segflg, int mode);
 int	kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg,
 	    int mode);
+int	kern_mkfifoat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, int mode);
 int	kern_mknod(struct thread *td, char *path, enum uio_seg pathseg,
 	    int mode, int dev);
+int	kern_mknodat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, int mode, int dev);
 int	kern_msgctl(struct thread *, int, int, struct msqid_ds *);
 int	kern_msgsnd(struct thread *, int, const void *, size_t, int, long);
 int	kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *);
@@ -121,6 +141,8 @@
 	    struct timespec *rmt);
 int	kern_open(struct thread *td, char *path, enum uio_seg pathseg,
 	    int flags, int mode);
+int	kern_openat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, int flags, int mode);
 int	kern_pathconf(struct thread *td, char *path, enum uio_seg pathseg,
 	    int name);
 int	kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset);
@@ -129,12 +151,17 @@
 int	kern_pwritev(struct thread *td, int fd, struct uio *auio, off_t offset);
 int	kern_readlink(struct thread *td, char *path, enum uio_seg pathseg,
 	    char *buf, enum uio_seg bufseg, int count);
+int	kern_readlinkat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, char *buf, enum uio_seg bufseg, int count);
 int	kern_readv(struct thread *td, int fd, struct uio *auio);
 int	kern_recvit(struct thread *td, int s, struct msghdr *mp,
 	    enum uio_seg fromseg, struct mbuf **controlp);
 int	kern_rename(struct thread *td, char *from, char *to,
 	    enum uio_seg pathseg);
+int	kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
+	    const char *new, enum uio_seg pathseg);
 int	kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg);
+int	kern_rmdirat(struct thread *td, int fd, const char *path, enum uio_seg pathseg);
 int	kern_sched_rr_get_interval(struct thread *td, pid_t pid,
 	    struct timespec *ts);
 int	kern_semctl(struct thread *td, int semid, int semnum, int cmd,
@@ -165,17 +192,24 @@
 int	kern_sigsuspend(struct thread *td, sigset_t mask);
 int	kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct stat *sbp);
+int	kern_statat(struct thread *td, int fd, const char *path,
+	    enum uio_seg pathseg, struct stat *sbp);
 int	kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct statfs *buf);
 int	kern_symlink(struct thread *td, char *path, char *link,
 	    enum uio_seg segflg);
+int	kern_symlinkat(struct thread *td, const char *path1, int fd,
+	    const char *path2, enum uio_seg segflg);
 int	kern_thr_new(struct thread *td, struct thr_param *param);
 int	kern_thr_suspend(struct thread *td, struct timespec *tsp);
 int	kern_truncate(struct thread *td, char *path, enum uio_seg pathseg,
 	    off_t length);
 int	kern_unlink(struct thread *td, char *path, enum uio_seg pathseg);
+int	kern_unlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg);
 int	kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct timeval *tptr, enum uio_seg tptrseg);
+int	kern_utimesat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
+	    const struct timeval *tptr, enum uio_seg tptrseg);
 int	kern_wait(struct thread *td, pid_t pid, int *status, int options,
 	    struct rusage *rup);
 int	kern_writev(struct thread *td, int fd, struct uio *auio);
--- sys/sysproto.h.orig
+++ sys/sysproto.h
@@ -2,7 +2,7 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/sysproto.h,v 1.214 2007/07/04 22:49:55 peter Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.232 2007/07/04 22:47:37 peter Exp 
  */
 
@@ -1515,6 +1515,92 @@
 	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
 	char length_l_[PADL_(off_t)]; off_t length; char length_r_[PADR_(off_t)];
 };
+struct faccessat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct fchmodat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct fchownat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char uid_l_[PADL_(uid_t)]; uid_t uid; char uid_r_[PADR_(uid_t)];
+	char gid_l_[PADL_(gid_t)]; gid_t gid; char gid_r_[PADR_(gid_t)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct fexecve_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char argv_l_[PADL_(char **)]; char ** argv; char argv_r_[PADR_(char **)];
+	char envv_l_[PADL_(char **)]; char ** envv; char envv_r_[PADR_(char **)];
+};
+struct fstatat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char buf_l_[PADL_(struct stat *)]; struct stat * buf; char buf_r_[PADR_(struct stat *)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct futimesat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char times_l_[PADL_(const struct timeval *)]; const struct timeval * times; char times_r_[PADR_(const struct timeval *)];
+};
+struct linkat_args {
+	char fd1_l_[PADL_(int)]; int fd1; char fd1_r_[PADR_(int)];
+	char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+	char fd2_l_[PADL_(int)]; int fd2; char fd2_r_[PADR_(int)];
+	char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct mkdirat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+};
+struct mkfifoat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+};
+struct mknodat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+	char dev_l_[PADL_(dev_t)]; dev_t dev; char dev_r_[PADR_(dev_t)];
+};
+struct openat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+	char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+};
+struct readlinkat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+	char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)];
+};
+struct renameat_args {
+	char oldfd_l_[PADL_(int)]; int oldfd; char oldfd_r_[PADR_(int)];
+	char old_l_[PADL_(const char *)]; const char * old; char old_r_[PADR_(const char *)];
+	char newfd_l_[PADL_(int)]; int newfd; char newfd_r_[PADR_(int)];
+	char new_l_[PADL_(const char *)]; const char * new; char new_r_[PADR_(const char *)];
+};
+struct symlinkat_args {
+	char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+};
+struct unlinkat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+	char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
 int	nosys(struct thread *, struct nosys_args *);
 void	sys_exit(struct thread *, struct sys_exit_args *);
 int	fork(struct thread *, struct fork_args *);
@@ -1853,6 +1939,21 @@
 int	lseek(struct thread *, struct lseek_args *);
 int	truncate(struct thread *, struct truncate_args *);
 int	ftruncate(struct thread *, struct ftruncate_args *);
+int	faccessat(struct thread *, struct faccessat_args *);
+int	fchmodat(struct thread *, struct fchmodat_args *);
+int	fchownat(struct thread *, struct fchownat_args *);
+int	fexecve(struct thread *, struct fexecve_args *);
+int	fstatat(struct thread *, struct fstatat_args *);
+int	futimesat(struct thread *, struct futimesat_args *);
+int	linkat(struct thread *, struct linkat_args *);
+int	mkdirat(struct thread *, struct mkdirat_args *);
+int	mkfifoat(struct thread *, struct mkfifoat_args *);
+int	mknodat(struct thread *, struct mknodat_args *);
+int	openat(struct thread *, struct openat_args *);
+int	readlinkat(struct thread *, struct readlinkat_args *);
+int	renameat(struct thread *, struct renameat_args *);
+int	symlinkat(struct thread *, struct symlinkat_args *);
+int	unlinkat(struct thread *, struct unlinkat_args *);
 
 #ifdef COMPAT_43
 
@@ -2416,6 +2517,21 @@
 #define	SYS_AUE_lseek	AUE_LSEEK
 #define	SYS_AUE_truncate	AUE_TRUNCATE
 #define	SYS_AUE_ftruncate	AUE_FTRUNCATE
+#define	SYS_AUE_faccessat	AUE_ACCESS
+#define	SYS_AUE_fchmodat	AUE_CHMOD
+#define	SYS_AUE_fchownat	AUE_CHOWN
+#define	SYS_AUE_fexecve	AUE_EXECVE
+#define	SYS_AUE_fstatat	AUE_STAT
+#define	SYS_AUE_futimesat	AUE_UTIMES
+#define	SYS_AUE_linkat	AUE_LINK
+#define	SYS_AUE_mkdirat	AUE_MKDIR
+#define	SYS_AUE_mkfifoat	AUE_MKFIFO
+#define	SYS_AUE_mknodat	AUE_MKNOD
+#define	SYS_AUE_openat	AUE_OPEN_RWTC
+#define	SYS_AUE_readlinkat	AUE_READLINK
+#define	SYS_AUE_renameat	AUE_RENAME
+#define	SYS_AUE_symlinkat	AUE_SYMLINK
+#define	SYS_AUE_unlinkat	AUE_UNLINK
 
 #undef PAD_
 #undef PADL_
--- sys/time.h.orig
+++ sys/time.h
@@ -320,6 +320,7 @@
 int	setitimer(int, const struct itimerval *, struct itimerval *);
 int	settimeofday(const struct timeval *, const struct timezone *);
 int	utimes(const char *, const struct timeval *);
+int	futimesat(int, const char *, const struct timeval [2]);
 __END_DECLS
 
 #endif /* !_KERNEL */
---  //depot/vendor/freebsd/src/include/stdio.h.orig
+++  ../include/stdio.h
@@ -447,5 +447,6 @@
 #define	putchar_unlocked(x)	putc_unlocked(x, stdout)
 #endif
 
+int	 renameat(int, const char *, int, const char *);
 __END_DECLS
 #endif /* !_STDIO_H_ */
---  //depot/vendor/freebsd/src/include/unistd.h.orig
+++  ../include/unistd.h
@@ -558,6 +558,15 @@
 extern int optreset;			/* getopt(3) external variable */
 #endif
 #endif /* __BSD_VISIBLE */
+
+int	faccessat(int, const char *, int);
+int	fchmodat(int, const char *, mode_t, int);
+int	fchownat(int, const char *, uid_t, gid_t, int);
+int	fexecve(int, char *const [], char *const []);
+int	linkat(int, const char *, int, const char *, int);
+ssize_t	readlinkat(int, const char *, char *, size_t);
+int	symlinkat(const char *, int, const char *);
+int	unlinkat(int, const char *, int);
 __END_DECLS
 
 #endif /* !_UNISTD_H_ */
---  //depot/vendor/freebsd/src/lib/libc/gen/Makefile.inc.orig
+++  ../lib/libc/gen/Makefile.inc
@@ -10,7 +10,7 @@
 	clock.c closedir.c confstr.c \
 	crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \
 	dlfcn.c dlfunc.c drand48.c erand48.c err.c errlst.c errno.c \
-	exec.c fmtcheck.c fmtmsg.c fnmatch.c \
+	exec.c fdopendir.c fmtcheck.c fmtmsg.c fnmatch.c \
 	fpclassify.c frexp.c fstab.c ftok.c fts.c ftw.c \
 	getbootfile.c getbsize.c \
 	getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \
--- /dev/null	Thu Jul  5 15:22:00 2007
+++ ../lib/libc/gen/fdopendir.c	Thu Jul  5 15:22:50 2007
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  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.
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)opendir.c	8.8 (Berkeley) 5/1/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "telldir.h"
+/*
+ * Open a directory.
+ */
+DIR *
+fdopendir(fd)
+	const int fd;
+{
+
+	return (__fdopendir2(fd, DTF_HIDEW|DTF_NODUP));
+}
+
+DIR *
+__fdopendir2(fd, flags)
+	const int fd;
+	int flags;
+{
+	DIR *dirp;
+	int incr;
+	int saved_errno;
+	int unionstack;
+	struct stat statb;
+
+	dirp = NULL;
+	if (_fstat(fd, &statb) != 0)
+		goto fail;
+	if (!S_ISDIR(statb.st_mode)) {
+		errno = ENOTDIR;
+		goto fail;
+	}
+	if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
+	    (dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL)
+		goto fail;
+
+	dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR));
+	LIST_INIT(&dirp->dd_td->td_locq);
+	dirp->dd_td->td_loccnt = 0;
+
+	/*
+	 * Use the system page size if that is a multiple of DIRBLKSIZ.
+	 * Hopefully this can be a big win someday by allowing page
+	 * trades to user space to be done by _getdirentries().
+	 */
+	incr = getpagesize();
+	if ((incr % DIRBLKSIZ) != 0) 
+		incr = DIRBLKSIZ;
+
+	/*
+	 * Determine whether this directory is the top of a union stack.
+	 */
+	if (flags & DTF_NODUP) {
+		struct statfs sfb;
+
+		if (_fstatfs(fd, &sfb) < 0)
+			goto fail;
+		unionstack = !strcmp(sfb.f_fstypename, "unionfs")
+		    || (sfb.f_flags & MNT_UNION);
+	} else {
+		unionstack = 0;
+	}
+
+	if (unionstack) {
+		int len = 0;
+		int space = 0;
+		char *buf = 0;
+		char *ddptr = 0;
+		char *ddeptr;
+		int n;
+		struct dirent **dpv;
+
+		/*
+		 * The strategy here is to read all the directory
+		 * entries into a buffer, sort the buffer, and
+		 * remove duplicate entries by setting the inode
+		 * number to zero.
+		 */
+
+		do {
+			/*
+			 * Always make at least DIRBLKSIZ bytes
+			 * available to _getdirentries
+			 */
+			if (space < DIRBLKSIZ) {
+				space += incr;
+				len += incr;
+				buf = reallocf(buf, len);
+				if (buf == NULL)
+					goto fail;
+				ddptr = buf + (len - space);
+			}
+
+			n = _getdirentries(fd, ddptr, space, &dirp->dd_seek);
+			if (n > 0) {
+				ddptr += n;
+				space -= n;
+			}
+		} while (n > 0);
+
+		ddeptr = ddptr;
+		flags |= __DTF_READALL;
+
+		/*
+		 * Re-open the directory.
+		 * This has the effect of rewinding back to the
+		 * top of the union stack and is needed by
+		 * programs which plan to fchdir to a descriptor
+		 * which has also been read -- see fts.c.
+		 */
+		if (flags & DTF_REWIND) {
+		/* XXX: what here? */
+		}
+
+		/*
+		 * There is now a buffer full of (possibly) duplicate
+		 * names.
+		 */
+		dirp->dd_buf = buf;
+
+		/*
+		 * Go round this loop twice...
+		 *
+		 * Scan through the buffer, counting entries.
+		 * On the second pass, save pointers to each one.
+		 * Then sort the pointers and remove duplicate names.
+		 */
+		for (dpv = 0;;) {
+			n = 0;
+			ddptr = buf;
+			while (ddptr < ddeptr) {
+				struct dirent *dp;
+
+				dp = (struct dirent *) ddptr;
+				if ((long)dp & 03L)
+					break;
+				if ((dp->d_reclen <= 0) ||
+				    (dp->d_reclen > (ddeptr + 1 - ddptr)))
+					break;
+				ddptr += dp->d_reclen;
+				if (dp->d_fileno) {
+					if (dpv)
+						dpv[n] = dp;
+					n++;
+				}
+			}
+
+			if (dpv) {
+				struct dirent *xp;
+
+				/*
+				 * This sort must be stable.
+				 */
+				mergesort(dpv, n, sizeof(*dpv), alphasort);
+
+				dpv[n] = NULL;
+				xp = NULL;
+
+				/*
+				 * Scan through the buffer in sort order,
+				 * zapping the inode number of any
+				 * duplicate names.
+				 */
+				for (n = 0; dpv[n]; n++) {
+					struct dirent *dp = dpv[n];
+
+					if ((xp == NULL) ||
+					    strcmp(dp->d_name, xp->d_name)) {
+						xp = dp;
+					} else {
+						dp->d_fileno = 0;
+					}
+					if (dp->d_type == DT_WHT &&
+					    (flags & DTF_HIDEW))
+						dp->d_fileno = 0;
+				}
+
+				free(dpv);
+				break;
+			} else {
+				dpv = malloc((n+1) * sizeof(struct dirent *));
+				if (dpv == NULL)
+					break;
+			}
+		}
+
+		dirp->dd_len = len;
+		dirp->dd_size = ddptr - dirp->dd_buf;
+	} else {
+		dirp->dd_len = incr;
+		dirp->dd_size = 0;
+		dirp->dd_buf = malloc(dirp->dd_len);
+		if (dirp->dd_buf == NULL)
+			goto fail;
+		dirp->dd_seek = 0;
+		flags &= ~DTF_REWIND;
+	}
+
+	dirp->dd_loc = 0;
+	dirp->dd_fd = fd;
+	dirp->dd_flags = flags;
+	dirp->dd_lock = NULL;
+
+	/*
+	 * Set up seek point for rewinddir.
+	 */
+	dirp->dd_rewind = telldir(dirp);
+
+	return (dirp);
+
+fail:
+	saved_errno = errno;
+	free(dirp);
+	errno = saved_errno;
+	return (NULL);
+}
---  //depot/vendor/freebsd/src/include/dirent.h.orig
+++  ../include/dirent.h
@@ -94,11 +94,13 @@
 __BEGIN_DECLS
 #if __BSD_VISIBLE
 DIR	*__opendir2(const char *, int);
+DIR	*__fdopendir2(int, int);
 int	 alphasort(const void *, const void *);
 int	 getdents(int, char *, int);
 int	 getdirentries(int, char *, int, long *);
 #endif
 DIR	*opendir(const char *);
+DIR	*fdopendir(int);
 struct dirent *
 	 readdir(DIR *);
 #if __POSIX_VISIBLE >= 199506 || __XSI_VISIBLE >= 500
