summaryrefslogtreecommitdiff
path: root/sys/compat/linux/common/linux_file.c
diff options
context:
space:
mode:
authorfvdl <fvdl@NetBSD.org>1995-10-08 22:53:43 +0000
committerfvdl <fvdl@NetBSD.org>1995-10-08 22:53:43 +0000
commit82079ba5b348e23d75a2b0789c52d50c8cf8db14 (patch)
treebb25e2d4a3cdd4cd97c9d82884905f8ee4f2c1df /sys/compat/linux/common/linux_file.c
parentf8b730af38581bb18bd3ebf7d2c0ff7baf815c18 (diff)
Work around calling the NetBSD fcntl(F_{G,S}ETOWN) for now; it is too
restrictive to implement the Linux equivalent (and perhaps too restrictive overall).
Diffstat (limited to 'sys/compat/linux/common/linux_file.c')
-rw-r--r--sys/compat/linux/common/linux_file.c57
1 files changed, 51 insertions, 6 deletions
diff --git a/sys/compat/linux/common/linux_file.c b/sys/compat/linux/common/linux_file.c
index 26e7e0bd7a9..c05a89916f2 100644
--- a/sys/compat/linux/common/linux_file.c
+++ b/sys/compat/linux/common/linux_file.c
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_file.c,v 1.12 1995/10/07 06:27:05 mycroft Exp $ */
+/* $NetBSD: linux_file.c,v 1.13 1995/10/08 22:53:43 fvdl Exp $ */
/*
* Copyright (c) 1995 Frank van der Linden
@@ -42,6 +42,9 @@
#include <sys/kernel.h>
#include <sys/mount.h>
#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
#include <sys/syscallargs.h>
@@ -293,6 +296,13 @@ linux_sys_fcntl(p, v, retval)
struct linux_flock lfl;
struct flock *bfp, bfl;
struct sys_fcntl_args fca;
+ struct filedesc *fdp;
+ struct file *fp;
+ struct vnode *vp;
+ struct vattr va;
+ long pgid;
+ struct pgrp *pgrp;
+ struct tty *tp, *(*d_tty) __P((dev_t));
fd = SCARG(uap, fd);
cmd = SCARG(uap, cmd);
@@ -351,11 +361,46 @@ linux_sys_fcntl(p, v, retval)
return sys_fcntl(p, &fca, retval);
break;
case LINUX_F_SETOWN:
- cmd = F_SETOWN;
- break;
- case LINUX_F_GETOWN:
- cmd = F_GETOWN;
- break;
+ case LINUX_F_GETOWN:
+ /*
+ * We need to route around the normal fcntl() for these calls,
+ * since it uses TIOC{G,S}PGRP, which is too restrictive for
+ * Linux F_{G,S}ETOWN semantics. For sockets, this problem
+ * does not exist.
+ */
+ fdp = p->p_fd;
+ if ((u_int)fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL)
+ return EBADF;
+ if (fp->f_type == DTYPE_SOCKET) {
+ cmd = cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
+ break;
+ }
+ vp = (struct vnode *)fp->f_data;
+ if (vp->v_type != VCHR)
+ return EINVAL;
+ if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
+ return error;
+ d_tty = cdevsw[major(va.va_rdev)].d_tty;
+ if (!d_tty || (!(tp = (*d_tty)(va.va_rdev))))
+ return EINVAL;
+ if (cmd == LINUX_F_GETOWN) {
+ retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
+ return 0;
+ }
+ if ((long)arg <= 0) {
+ pgid = -(long)arg;
+ } else {
+ struct proc *p1 = pfind((long)arg);
+ if (p1 == 0)
+ return (ESRCH);
+ pgid = (long)p1->p_pgrp->pg_id;
+ }
+ pgrp = pgfind(pgid);
+ if (pgrp == NULL || pgrp->pg_session != p->p_session)
+ return EPERM;
+ tp->t_pgrp = pgrp;
+ return 0;
default:
return EOPNOTSUPP;
}