Index: emulation/linux/linux_file.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/linux/linux_file.c,v
retrieving revision 1.9
diff -u -u -r1.9 linux_file.c
--- emulation/linux/linux_file.c	15 Aug 2003 06:32:51 -0000	1.9
+++ emulation/linux/linux_file.c	13 Oct 2003 09:16:40 -0000
@@ -38,6 +38,7 @@
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
+#include <sys/kern_syscall.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
@@ -915,108 +916,54 @@
 #endif
 
 static int
-fcntl_common(struct linux_fcntl64_args *args)
+linux_fcntl_common(struct linux_fcntl64_args *args)
 {
 	struct proc *p = curproc;
 	struct l_flock linux_flock;
-	struct flock *bsd_flock;
-	struct fcntl_args fcntl_args;
 	struct filedesc *fdp;
 	struct file *fp;
-	int error, result;
-	caddr_t sg;
-
-	sg = stackgap_init();
-	bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock));
-
-	fcntl_args.fd = args->fd;
-	fcntl_args.sysmsg_result = 0;
+	union fcntl_dat dat;
+	int error, cmd;
 
 	switch (args->cmd) {
 	case LINUX_F_DUPFD:
-		fcntl_args.cmd = F_DUPFD;
-		fcntl_args.arg = args->arg;
+		cmd = F_DUPFD;
+		dat.fc_fd = args->arg;
 		break;
 	case LINUX_F_GETFD:
-		fcntl_args.cmd = F_GETFD;
+		cmd = F_GETFD;
 		break;
 	case LINUX_F_SETFD:
-		fcntl_args.cmd = F_SETFD;
-		fcntl_args.arg = args->arg;
+		cmd = F_SETFD;
+		dat.fc_cloexec = args->arg;
 		break;
 	case LINUX_F_GETFL:
-		fcntl_args.cmd = F_GETFL;
-		error = fcntl(&fcntl_args);
-		result = fcntl_args.sysmsg_result;
-		args->sysmsg_result = 0;
-		if (result & O_RDONLY)
-			args->sysmsg_result |= LINUX_O_RDONLY;
-		if (result & O_WRONLY)
-			args->sysmsg_result |= LINUX_O_WRONLY;
-		if (result & O_RDWR)
-			args->sysmsg_result |= LINUX_O_RDWR;
-		if (result & O_NDELAY)
-			args->sysmsg_result |= LINUX_O_NONBLOCK;
-		if (result & O_APPEND)
-			args->sysmsg_result |= LINUX_O_APPEND;
-		if (result & O_FSYNC)
-			args->sysmsg_result |= LINUX_O_SYNC;
-		if (result & O_ASYNC)
-			args->sysmsg_result |= LINUX_FASYNC;
-		return (error);
-
+		cmd = F_GETFL;
+		break;
 	case LINUX_F_SETFL:
-		fcntl_args.arg = 0;
+		cmd = F_SETFL;
+		dat.fc_flags = 0;
 		if (args->arg & LINUX_O_NDELAY)
-			fcntl_args.arg |= O_NONBLOCK;
+			dat.fc_flags |= O_NONBLOCK;
 		if (args->arg & LINUX_O_APPEND)
-			fcntl_args.arg |= O_APPEND;
+			dat.fc_flags |= O_APPEND;
 		if (args->arg & LINUX_O_SYNC)
-			fcntl_args.arg |= O_FSYNC;
+			dat.fc_flags |= O_FSYNC;
 		if (args->arg & LINUX_FASYNC)
-			fcntl_args.arg |= O_ASYNC;
-		fcntl_args.cmd = F_SETFL;
+			dat.fc_flags |= O_ASYNC;
 		break;
-
 	case LINUX_F_GETLK:
-		error = copyin((caddr_t)args->arg, &linux_flock,
-		    sizeof(linux_flock));
-		if (error)
-			return (error);
-		linux_to_bsd_flock(&linux_flock, bsd_flock);
-		fcntl_args.fd = args->fd;
-		fcntl_args.cmd = F_GETLK;
-		fcntl_args.arg = (long)bsd_flock;
-		error = fcntl(&fcntl_args);
-		args->sysmsg_result = fcntl_args.sysmsg_result;
-		if (error)
-			return (error);
-		bsd_to_linux_flock(bsd_flock, &linux_flock);
-		return (copyout(&linux_flock, (caddr_t)args->arg,
-		    sizeof(linux_flock)));
-
 	case LINUX_F_SETLK:
-		error = copyin((caddr_t)args->arg, &linux_flock,
-		    sizeof(linux_flock));
-		if (error)
-			return (error);
-		linux_to_bsd_flock(&linux_flock, bsd_flock);
-		fcntl_args.fd = args->fd;
-		fcntl_args.cmd = F_SETLK;
-		fcntl_args.arg = (long)bsd_flock;
-		break;
 	case LINUX_F_SETLKW:
+		cmd = F_GETLK;
 		error = copyin((caddr_t)args->arg, &linux_flock,
 		    sizeof(linux_flock));
 		if (error)
 			return (error);
-		linux_to_bsd_flock(&linux_flock, bsd_flock);
-		fcntl_args.fd = args->fd;
-		fcntl_args.cmd = F_SETLKW;
-		fcntl_args.arg = (long)bsd_flock;
+		linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
 		break;
 	case LINUX_F_GETOWN:
-		fcntl_args.cmd = F_GETOWN;
+		cmd = F_GETOWN;
 		break;
 	case LINUX_F_SETOWN:
 		/*
@@ -1030,14 +977,58 @@
 			return (EBADF);
 		if (fp->f_type == DTYPE_PIPE)
 			return (EINVAL);
-		fcntl_args.cmd = F_SETOWN;
-		fcntl_args.arg = args->arg;
+		cmd = F_SETOWN;
+		dat.fc_owner = args->arg;
 		break;
 	default:
 		return (EINVAL);
 	}
-	error = fcntl(&fcntl_args);
-	args->sysmsg_result = fcntl_args.sysmsg_result;
+
+	error = kern_fcntl(args->fd, cmd, &dat);
+
+	if (error == 0) {
+		switch (args->cmd) {
+		case LINUX_F_DUPFD:
+			args->sysmsg_result = dat.fc_fd;
+			break;
+		case LINUX_F_GETFD:
+			args->sysmsg_result = dat.fc_cloexec;
+			break;
+		case LINUX_F_SETFD:
+			break;
+		case LINUX_F_GETFL:
+			args->sysmsg_result = 0;
+			if (dat.fc_flags & O_RDONLY)
+				args->sysmsg_result |= LINUX_O_RDONLY;
+			if (dat.fc_flags & O_WRONLY)
+				args->sysmsg_result |= LINUX_O_WRONLY;
+			if (dat.fc_flags & O_RDWR)
+				args->sysmsg_result |= LINUX_O_RDWR;
+			if (dat.fc_flags & O_NDELAY)
+				args->sysmsg_result |= LINUX_O_NONBLOCK;
+			if (dat.fc_flags & O_APPEND)
+				args->sysmsg_result |= LINUX_O_APPEND;
+			if (dat.fc_flags & O_FSYNC)
+				args->sysmsg_result |= LINUX_O_SYNC;
+			if (dat.fc_flags & O_ASYNC)
+				args->sysmsg_result |= LINUX_FASYNC;
+			break;
+		case LINUX_F_GETLK:
+			bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
+			error = copyout(&linux_flock, (caddr_t)args->arg,
+			    sizeof(linux_flock));
+			break;
+		case LINUX_F_SETLK:
+		case LINUX_F_SETLKW:
+			break;
+		case LINUX_F_GETOWN:
+			args->sysmsg_result = dat.fc_owner;
+			break;
+		case LINUX_F_SETOWN:
+			break;
+		}
+	}
+
 	return(error);
 }
 
@@ -1056,7 +1047,7 @@
 	args64.cmd = args->cmd;
 	args64.arg = args->arg;
 	args64.sysmsg_result = 0;
-	error = fcntl_common(&args64);
+	error = linux_fcntl_common(&args64);
 	args->sysmsg_result = args64.sysmsg_result;
 	return(error);
 }
@@ -1065,67 +1056,46 @@
 int
 linux_fcntl64(struct linux_fcntl64_args *args)
 {
-	struct fcntl_args fcntl_args;
 	struct l_flock64 linux_flock;
-	struct flock *bsd_flock;
-	int error;
-	caddr_t sg;
-
-	sg = stackgap_init();
-	bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock));
+	union fcntl_dat dat;
+	int error, cmd = 0;
 
 #ifdef DEBUG
 	if (ldebug(fcntl64))
 		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
 #endif
-	fcntl_args.sysmsg_result = 0;
+	if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
+	    args->cmd == LINUX_F_SETLKW64) {
+		switch (args->cmd) {
+		case LINUX_F_GETLK64:
+			cmd = F_GETLK;
+			break;
+		case LINUX_F_SETLK64:
+			cmd = F_SETLK;
+			break;
+		case LINUX_F_SETLKW64:
+			cmd = F_SETLKW;
+			break;
+		}
 
-	switch (args->cmd) {
-	case LINUX_F_GETLK64:
 		error = copyin((caddr_t)args->arg, &linux_flock,
 		    sizeof(linux_flock));
 		if (error)
 			return (error);
-		linux_to_bsd_flock64(&linux_flock, bsd_flock);
-		fcntl_args.fd = args->fd;
-		fcntl_args.cmd = F_GETLK;
-		fcntl_args.arg = (long)bsd_flock;
-		error = fcntl(&fcntl_args);
-		args->sysmsg_result = fcntl_args.sysmsg_result;
-		if (error)
-			return (error);
-		bsd_to_linux_flock64(bsd_flock, &linux_flock);
-		return (copyout(&linux_flock, (caddr_t)args->arg,
-		    sizeof(linux_flock)));
+		linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
 
-	case LINUX_F_SETLK64:
-		error = copyin((caddr_t)args->arg, &linux_flock,
-		    sizeof(linux_flock));
-		if (error)
-			return (error);
-		linux_to_bsd_flock64(&linux_flock, bsd_flock);
-		fcntl_args.fd = args->fd;
-		fcntl_args.cmd = F_SETLK;
-		fcntl_args.arg = (long)bsd_flock;
-		error = fcntl(&fcntl_args);
-		args->sysmsg_result = fcntl_args.sysmsg_result;
-		return(error);
+		error = kern_fcntl(args->fd, cmd, &dat);
 
-	case LINUX_F_SETLKW64:
-		error = copyin((caddr_t)args->arg, &linux_flock,
-		    sizeof(linux_flock));
-		if (error)
-			return (error);
-		linux_to_bsd_flock64(&linux_flock, bsd_flock);
-		fcntl_args.fd = args->fd;
-		fcntl_args.cmd = F_SETLKW;
-		fcntl_args.arg = (long)bsd_flock;
-		error = fcntl(&fcntl_args);
-		args->sysmsg_result = fcntl_args.sysmsg_result;
-		return(error);
+		if (error == 0 && args->cmd == LINUX_F_GETLK64) {
+			bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
+			error = copyout(&linux_flock, (caddr_t)args->arg,
+			    sizeof(linux_flock));
+		}
+	} else {
+		error = linux_fcntl_common(args);
 	}
 
-	return (fcntl_common(args));
+	return (error);
 }
 #endif /* __i386__ */
 
Index: emulation/linux/linux_socket.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/linux/linux_socket.c,v
retrieving revision 1.14
diff -u -u -r1.14 linux_socket.c
--- emulation/linux/linux_socket.c	13 Oct 2003 04:58:13 -0000	1.14
+++ emulation/linux/linux_socket.c	13 Oct 2003 09:19:27 -0000
@@ -421,11 +421,6 @@
 linux_accept(struct linux_accept_args *args, int *res)
 {
 	struct linux_accept_args linux_args;
-	struct fcntl_args /* {
-		int fd;
-		int cmd;
-		long arg;
-	} */ f_args;
 	struct sockaddr *sa = NULL;
 	int error, sa_len;
 
@@ -470,10 +465,7 @@
 	 * accepted one, so we must clear the flags in the new descriptor.
 	 * Ignore any errors, because we already have an open fd.
 	 */
-	f_args.fd = *res;
-	f_args.cmd = F_SETFL;
-	f_args.arg = 0;
-	(void)fcntl(&f_args);
+	kern_fcntl(*res, F_SETFL, 0);
 	return (0);
 }
 
Index: kern/kern_descrip.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/kern_descrip.c,v
retrieving revision 1.15
diff -u -u -r1.15 kern_descrip.c
--- kern/kern_descrip.c	13 Oct 2003 21:15:43 -0000	1.15
+++ kern/kern_descrip.c	14 Oct 2003 00:52:32 -0000
@@ -59,6 +59,7 @@
 #include <sys/unistd.h>
 #include <sys/resourcevar.h>
 #include <sys/event.h>
+#include <sys/kern_syscall.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
@@ -94,7 +95,6 @@
 	/* psize */	nopsize
 };
 
-static int do_dup (struct filedesc *fdp, int old, int new, register_t *retval, struct proc *p);
 static int badfo_readwrite (struct file *fp, struct uio *uio,
     struct ucred *cred, int flags, struct thread *td);
 static int badfo_ioctl (struct file *fp, u_long com, caddr_t data,
@@ -136,31 +136,11 @@
 int
 dup2(struct dup2_args *uap)
 {
-	struct proc *p = curproc;
-	struct filedesc *fdp = p->p_fd;
-	u_int old = uap->from, new = uap->to;
-	int i, error;
+	int error;
 
-retry:
-	if (old >= fdp->fd_nfiles ||
-	    fdp->fd_ofiles[old] == NULL ||
-	    new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
-	    new >= maxfilesperproc) {
-		return (EBADF);
-	}
-	if (old == new) {
-		uap->sysmsg_result = new;
-		return (0);
-	}
-	if (new >= fdp->fd_nfiles) {
-		if ((error = fdalloc(p, new, &i)))
-			return (error);
-		/*
-		 * fdalloc() may block, retest everything.
-		 */
-		goto retry;
-	}
-	return (do_dup(fdp, (int)old, (int)new, uap->sysmsg_fds, p));
+	error = kern_dup(DUP_FIXED, uap->from, uap->to, uap->sysmsg_fds);
+
+	return (error);
 }
 
 /*
@@ -170,26 +150,15 @@
 int
 dup(struct dup_args *uap)
 {
-	struct proc *p = curproc;
-	struct filedesc *fdp;
-	u_int old;
-	int new, error;
+	int error;
 
-	old = uap->fd;
-	fdp = p->p_fd;
-	if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL)
-		return (EBADF);
-	if ((error = fdalloc(p, 0, &new)))
-		return (error);
-	return (do_dup(fdp, (int)old, new, uap->sysmsg_fds, p));
+	error = kern_dup(DUP_VARIABLE, uap->fd, 0, uap->sysmsg_fds);
+
+	return (error);
 }
 
-/*
- * The file control system call.
- */
-/* ARGSUSED */
 int
-fcntl(struct fcntl_args *uap)
+kern_fcntl(int fd, int cmd, union fcntl_dat *dat)
 {
 	struct thread *td = curthread;
 	struct proc *p = td->td_proc;
@@ -197,44 +166,42 @@
 	struct file *fp;
 	char *pop;
 	struct vnode *vp;
-	int i, tmp, error, flg = F_POSIX;
-	struct flock fl;
 	u_int newmin;
+	int tmp, error, flg = F_POSIX;
 
 	KKASSERT(p);
 
-	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
-	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
+	if ((unsigned)fd >= fdp->fd_nfiles ||
+	    (fp = fdp->fd_ofiles[fd]) == NULL)
 		return (EBADF);
-	pop = &fdp->fd_ofileflags[uap->fd];
+	pop = &fdp->fd_ofileflags[fd];
 
-	switch (uap->cmd) {
+	switch (cmd) {
 	case F_DUPFD:
-		newmin = uap->arg;
+		newmin = dat->fc_fd;
 		if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
-		    newmin >= maxfilesperproc)
+		    newmin > maxfilesperproc)
 			return (EINVAL);
-		if ((error = fdalloc(p, newmin, &i)))
-			return (error);
-		return (do_dup(fdp, uap->fd, i, uap->sysmsg_fds, p));
+		error = kern_dup(DUP_VARIABLE, fd, newmin, &dat->fc_fd);
+		return (error);
 
 	case F_GETFD:
-		uap->sysmsg_result = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0;
+		dat->fc_cloexec = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0;
 		return (0);
 
 	case F_SETFD:
 		*pop = (*pop &~ UF_EXCLOSE) |
-		    (uap->arg & FD_CLOEXEC ? UF_EXCLOSE : 0);
+		    (dat->fc_cloexec & FD_CLOEXEC ? UF_EXCLOSE : 0);
 		return (0);
 
 	case F_GETFL:
-		uap->sysmsg_result = OFLAGS(fp->f_flag);
+		dat->fc_flags = OFLAGS(fp->f_flag);
 		return (0);
 
 	case F_SETFL:
 		fhold(fp);
 		fp->f_flag &= ~FCNTLFLAGS;
-		fp->f_flag |= FFLAGS(uap->arg & ~O_ACCMODE) & FCNTLFLAGS;
+		fp->f_flag |= FFLAGS(dat->fc_flags & ~O_ACCMODE) & FCNTLFLAGS;
 		tmp = fp->f_flag & FNONBLOCK;
 		error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, td);
 		if (error) {
@@ -249,19 +216,19 @@
 		}
 		fp->f_flag &= ~FNONBLOCK;
 		tmp = 0;
-		(void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, td);
+		fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, td);
 		fdrop(fp, td);
 		return (error);
 
 	case F_GETOWN:
 		fhold(fp);
-		error = fo_ioctl(fp, FIOGETOWN, (caddr_t)uap->sysmsg_fds, td);
+		error = fo_ioctl(fp, FIOGETOWN, (caddr_t)&dat->fc_owner, td);
 		fdrop(fp, td);
 		return(error);
 
 	case F_SETOWN:
 		fhold(fp);
-		error = fo_ioctl(fp, FIOSETOWN, (caddr_t)&uap->arg, td);
+		error = fo_ioctl(fp, FIOSETOWN, (caddr_t)&dat->fc_owner, td);
 		fdrop(fp, td);
 		return(error);
 
@@ -278,17 +245,10 @@
 		 * copyin/lockop may block
 		 */
 		fhold(fp);
-		/* Copy in the lock structure */
-		error = copyin((caddr_t)(intptr_t)uap->arg, (caddr_t)&fl,
-		    sizeof(fl));
-		if (error) {
-			fdrop(fp, td);
-			return (error);
-		}
-		if (fl.l_whence == SEEK_CUR)
-			fl.l_start += fp->f_offset;
+		if (dat->fc_flock.l_whence == SEEK_CUR)
+			dat->fc_flock.l_start += fp->f_offset;
 
-		switch (fl.l_type) {
+		switch (dat->fc_flock.l_type) {
 		case F_RDLCK:
 			if ((fp->f_flag & FREAD) == 0) {
 				error = EBADF;
@@ -296,7 +256,7 @@
 			}
 			p->p_leader->p_flag |= P_ADVLOCK;
 			error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK,
-			    &fl, flg);
+			    &dat->fc_flock, flg);
 			break;
 		case F_WRLCK:
 			if ((fp->f_flag & FWRITE) == 0) {
@@ -305,25 +265,25 @@
 			}
 			p->p_leader->p_flag |= P_ADVLOCK;
 			error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK,
-			    &fl, flg);
+			    &dat->fc_flock, flg);
 			break;
 		case F_UNLCK:
 			error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK,
-				&fl, F_POSIX);
+				&dat->fc_flock, F_POSIX);
 			break;
 		default:
 			error = EINVAL;
 			break;
 		}
 		/* Check for race with close */
-		if ((unsigned) uap->fd >= fdp->fd_nfiles ||
-		    fp != fdp->fd_ofiles[uap->fd]) {
-			fl.l_whence = SEEK_SET;
-			fl.l_start = 0;
-			fl.l_len = 0;
-			fl.l_type = F_UNLCK;
+		if ((unsigned) fd >= fdp->fd_nfiles ||
+		    fp != fdp->fd_ofiles[fd]) {
+			dat->fc_flock.l_whence = SEEK_SET;
+			dat->fc_flock.l_start = 0;
+			dat->fc_flock.l_len = 0;
+			dat->fc_flock.l_type = F_UNLCK;
 			(void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader,
-					   F_UNLCK, &fl, F_POSIX);
+					   F_UNLCK, &dat->fc_flock, F_POSIX);
 		}
 		fdrop(fp, td);
 		return(error);
@@ -336,27 +296,17 @@
 		 * copyin/lockop may block
 		 */
 		fhold(fp);
-		/* Copy in the lock structure */
-		error = copyin((caddr_t)(intptr_t)uap->arg, (caddr_t)&fl,
-		    sizeof(fl));
-		if (error) {
-			fdrop(fp, td);
-			return (error);
-		}
-		if (fl.l_type != F_RDLCK && fl.l_type != F_WRLCK &&
-		    fl.l_type != F_UNLCK) {
+		if (dat->fc_flock.l_type != F_RDLCK &&
+		    dat->fc_flock.l_type != F_WRLCK &&
+		    dat->fc_flock.l_type != F_UNLCK) {
 			fdrop(fp, td);
 			return (EINVAL);
 		}
-		if (fl.l_whence == SEEK_CUR)
-			fl.l_start += fp->f_offset;
+		if (dat->fc_flock.l_whence == SEEK_CUR)
+			dat->fc_flock.l_start += fp->f_offset;
 		error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK,
-			    &fl, F_POSIX);
+			    &dat->fc_flock, F_POSIX);
 		fdrop(fp, td);
-		if (error == 0) {
-			error = copyout((caddr_t)&fl,
-				    (caddr_t)(intptr_t)uap->arg, sizeof(fl));
-		}
 		return(error);
 	default:
 		return (EINVAL);
@@ -365,19 +315,128 @@
 }
 
 /*
+ * The file control system call.
+ */
+int
+fcntl(struct fcntl_args *uap)
+{
+	union fcntl_dat dat;
+	int error;
+
+	switch (uap->cmd) {
+	case F_DUPFD:
+		dat.fc_fd = uap->arg;
+		break;
+	case F_SETFD:
+		dat.fc_cloexec = uap->arg;
+		break;
+	case F_SETFL:
+		dat.fc_flags = uap->arg;
+		break;
+	case F_SETOWN:
+		dat.fc_owner = uap->arg;
+		break;
+	case F_SETLKW:
+	case F_SETLK:
+	case F_GETLK:
+		error = copyin((caddr_t)uap->arg, &dat.fc_flock,
+		    sizeof(struct flock));
+		if (error)
+			return (error);
+		break;
+	}
+
+	error = kern_fcntl(uap->fd, uap->cmd, &dat);
+
+	if (error == 0) {
+		switch (uap->cmd) {
+		case F_DUPFD:
+			uap->sysmsg_result = dat.fc_fd;
+			break;
+		case F_GETFD:
+			uap->sysmsg_result = dat.fc_cloexec;
+			break;
+		case F_GETFL:
+			uap->sysmsg_result = dat.fc_flags;
+			break;
+		case F_GETOWN:
+			uap->sysmsg_result = dat.fc_owner;
+		case F_GETLK:
+			error = copyout(&dat.fc_flock, (caddr_t)uap->arg,
+			    sizeof(struct flock));
+			break;
+		}
+	}
+
+	return (error);
+}
+
+/*
  * Common code for dup, dup2, and fcntl(F_DUPFD).
+ *
+ * The type flag can be either DUP_FIXED or DUP_VARIABLE.  DUP_FIXED tells
+ * kern_dup() to destructively dup over an existing file descriptor if new
+ * is already open.  DUP_VARIABLE tells kern_dup() to find the lowest
+ * unused file descriptor that is greater than or equal to new.
  */
-static int
-do_dup(fdp, old, new, retval, p)
-	struct filedesc *fdp;
-	int old, new;
-	register_t *retval;
-	struct proc *p;
+int
+kern_dup(enum dup_type type, int old, int new, int *res)
 {
-	struct thread *td = p->p_thread;
+	struct thread *td = curthread;
+	struct proc *p = td->td_proc;
+	struct filedesc *fdp = p->p_fd;
 	struct file *fp;
 	struct file *delfp;
 	int holdleaders;
+	int error, newfd;
+
+	/*
+	 * Verify that we have a valid descriptor to dup from and
+	 * possibly to dup to.
+	 */
+	if (old < 0 || new < 0 || new > p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
+	    new >= maxfilesperproc)
+		return (EBADF);
+	if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL)
+		return (EBADF);
+	if (type == DUP_FIXED && old == new) {
+		*res = new;
+		return (0);
+	}
+	fp = fdp->fd_ofiles[old];
+	fhold(fp);
+
+	/*
+	 * Expand the table for the new descriptor if needed.  This may
+	 * block and drop and reacquire the fidedesc lock.
+	 */
+	if (type == DUP_VARIABLE || new >= fdp->fd_nfiles) {
+		error = fdalloc(p, new, &newfd);
+		if (error) {
+			fdrop(fp, td);
+			return (error);
+		}
+	}
+	if (type == DUP_VARIABLE)
+		new = newfd;
+
+	/*
+	 * If the old file changed out from under us then treat it as a
+	 * bad file descriptor.  Userland should do its own locking to
+	 * avoid this case.
+	 */
+	if (fdp->fd_ofiles[old] != fp) {
+		if (fdp->fd_ofiles[new] == NULL) {
+			if (new < fdp->fd_freefile)
+				fdp->fd_freefile = new;
+			while (fdp->fd_lastfile > 0 &&
+			    fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
+				fdp->fd_lastfile--;
+		}
+		fdrop(fp, td);
+		return (EBADF);
+	}
+	KASSERT(old != new, ("new fd is same as old"));
 
 	/*
 	 * Save info on the descriptor being overwritten.  We have
@@ -394,6 +453,8 @@
 		holdleaders = 1;
 	} else
 		holdleaders = 0;
+	KASSERT(delfp == NULL || type == DUP_FIXED,
+	    ("dup() picked an open file"));
 #if 0
 	if (delfp && (fdp->fd_ofileflags[new] & UF_MAPPED))
 		(void) munmapfd(p, new);
@@ -402,13 +463,11 @@
 	/*
 	 * Duplicate the source descriptor, update lastfile
 	 */
-	fp = fdp->fd_ofiles[old];
 	fdp->fd_ofiles[new] = fp;
 	fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
-	fhold(fp);
 	if (new > fdp->fd_lastfile)
 		fdp->fd_lastfile = new;
-	*retval = new;
+	*res = new;
 
 	/*
 	 * If we dup'd over a valid file, we now own the reference to it
@@ -752,10 +811,7 @@
 SYSCTL_INT(_debug, OID_AUTO, fdexpand, CTLFLAG_RD, &fdexpand, 0, "");
 
 int
-fdalloc(p, want, result)
-	struct proc *p;
-	int want;
-	int *result;
+fdalloc(struct proc *p, int want, int *result)
 {
 	struct filedesc *fdp = p->p_fd;
 	int i;
@@ -1331,10 +1387,7 @@
                        VOP_UNLOCK(nd.ni_vp, 0, td);
                        devnull = fd;
                } else {
-                       error = fdalloc(p, 0, &fd);
-                       if (error != 0)
-                               break;
-                       error = do_dup(fdp, devnull, fd, &retval, p);
+                       error = kern_dup(DUP_FIXED, devnull, i, &retval);
                        if (error != 0)
                                break;
                }
Index: sys/fcntl.h
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/sys/fcntl.h,v
retrieving revision 1.4
diff -u -u -r1.4 fcntl.h
--- sys/fcntl.h	13 Oct 2003 21:15:48 -0000	1.4
+++ sys/fcntl.h	14 Oct 2003 00:11:43 -0000
@@ -190,6 +190,16 @@
 	short	l_whence;	/* type of l_start */
 };
 
+#ifdef _KERNEL
+union fcntl_dat {
+	int		fc_fd;		/* F_DUPFD */
+	int		fc_cloexec;	/* F_GETFD/F_SETFD */
+	int		fc_flags;	/* F_GETFL/F_SETFL */
+	int		fc_owner;	/* F_GETOWN/F_SETOWN */
+	struct flock	fc_flock;	/* F_GETLK/F_SETLK */
+};
+#endif /* _KERNEL */
+
 
 #ifndef _POSIX_SOURCE
 /* lock operations for flock(2) */
Index: sys/kern_syscall.h
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/sys/kern_syscall.h,v
retrieving revision 1.5
diff -u -u -r1.5 kern_syscall.h
--- sys/kern_syscall.h	8 Oct 2003 01:30:32 -0000	1.5
+++ sys/kern_syscall.h	13 Oct 2003 23:40:34 -0000
@@ -31,6 +31,18 @@
 #ifndef _SYS_KERN_SYSCALL_H_
 #define _SYS_KERN_SYSCALL_H_
 
+/*
+ * Prototypes for syscalls in kern/kern_descrip.c
+ */
+enum dup_type {DUP_FIXED, DUP_VARIABLE};
+union fcntl_dat;
+
+int kern_dup(enum dup_type type, int old, int new, int *res);
+int kern_fcntl(int fd, int cmd, union fcntl_dat *dat);
+
+/*
+ * Prototypes for syscalls in kern/uipc_syscalls.c
+ */
 struct mbuf;
 struct msghdr;
 struct sf_hdtr;
