#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tty_tty.c,v 1.41 2020/05/23 23:42:43 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#define cttyvp(p) ((p)->p_lflag & PL_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
static int
cttyopen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct vnode *ttyvp = cttyvp(l->l_proc);
int error;
if (ttyvp == NULL)
return (ENXIO);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
#ifdef PARANOID
error = VOP_ACCESS(ttyvp,
(flag&FREAD ? VREAD : 0) | (flag&FWRITE ? VWRITE : 0), l->l_cred, l);
if (!error)
#endif
error = VOP_OPEN(ttyvp, flag, NOCRED);
VOP_UNLOCK(ttyvp);
return (error);
}
static int
cttyread(dev_t dev, struct uio *uio, int flag)
{
struct vnode *ttyvp = cttyvp(curproc);
int error;
if (ttyvp == NULL)
return (EIO);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_READ(ttyvp, uio, flag, NOCRED);
VOP_UNLOCK(ttyvp);
return (error);
}
static int
cttywrite(dev_t dev, struct uio *uio, int flag)
{
struct vnode *ttyvp = cttyvp(curproc);
int error;
if (ttyvp == NULL)
return (EIO);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
VOP_UNLOCK(ttyvp);
return (error);
}
static int
cttyioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
struct vnode *ttyvp = cttyvp(l->l_proc);
int rv;
if (ttyvp == NULL)
return (EIO);
if (cmd == TIOCSCTTY)
return (EINVAL);
if (cmd == TIOCNOTTY) {
mutex_enter(&proc_lock);
if (!SESS_LEADER(l->l_proc)) {
l->l_proc->p_lflag &= ~PL_CONTROLT;
rv = 0;
} else
rv = EINVAL;
mutex_exit(&proc_lock);
return (rv);
}
return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED));
}
static int
cttypoll(dev_t dev, int events, struct lwp *l)
{
struct vnode *ttyvp = cttyvp(l->l_proc);
if (ttyvp == NULL)
return (seltrue(dev, events, l));
return (VOP_POLL(ttyvp, events));
}
static int
cttykqfilter(dev_t dev, struct knote *kn)
{
struct proc *p = curproc;
struct vnode *ttyvp = cttyvp(p);
if (ttyvp == NULL)
return (1);
return (VOP_KQFILTER(ttyvp, kn));
}
const struct cdevsw ctty_cdevsw = {
.d_open = cttyopen,
.d_close = nullclose,
.d_read = cttyread,
.d_write = cttywrite,
.d_ioctl = cttyioctl,
.d_stop = nullstop,
.d_tty = notty,
.d_poll = cttypoll,
.d_mmap = nommap,
.d_kqfilter = cttykqfilter,
.d_discard = nodiscard,
.d_flag = D_TTY
};