| 2074 | } |
| 2075 | |
| 2076 | int |
| 2077 | ttyhook_register(struct tty **rtp, struct proc *p, int fd, struct ttyhook *th, |
| 2078 | void *softc) |
| 2079 | { |
| 2080 | struct tty *tp; |
| 2081 | struct file *fp; |
| 2082 | struct cdev *dev; |
| 2083 | struct cdevsw *cdp; |
| 2084 | struct filedesc *fdp; |
| 2085 | cap_rights_t rights; |
| 2086 | int error, ref; |
| 2087 | |
| 2088 | /* Validate the file descriptor. */ |
| 2089 | fdp = p->p_fd; |
| 2090 | error = fget_unlocked(fdp, fd, cap_rights_init_one(&rights, CAP_TTYHOOK), |
| 2091 | &fp); |
| 2092 | if (error != 0) |
| 2093 | return (error); |
| 2094 | if (fp->f_ops == &badfileops) { |
| 2095 | error = EBADF; |
| 2096 | goto done1; |
| 2097 | } |
| 2098 | |
| 2099 | /* |
| 2100 | * Make sure the vnode is bound to a character device. |
| 2101 | * Unlocked check for the vnode type is ok there, because we |
| 2102 | * only shall prevent calling devvn_refthread on the file that |
| 2103 | * never has been opened over a character device. |
| 2104 | */ |
| 2105 | if (fp->f_type != DTYPE_VNODE || fp->f_vnode->v_type != VCHR) { |
| 2106 | error = EINVAL; |
| 2107 | goto done1; |
| 2108 | } |
| 2109 | |
| 2110 | /* Make sure it is a TTY. */ |
| 2111 | cdp = devvn_refthread(fp->f_vnode, &dev, &ref); |
| 2112 | if (cdp == NULL) { |
| 2113 | error = ENXIO; |
| 2114 | goto done1; |
| 2115 | } |
| 2116 | if (dev != fp->f_data) { |
| 2117 | error = ENXIO; |
| 2118 | goto done2; |
| 2119 | } |
| 2120 | if (cdp != &ttydev_cdevsw) { |
| 2121 | error = ENOTTY; |
| 2122 | goto done2; |
| 2123 | } |
| 2124 | tp = dev->si_drv1; |
| 2125 | |
| 2126 | /* Try to attach the hook to the TTY. */ |
| 2127 | error = EBUSY; |
| 2128 | tty_lock(tp); |
| 2129 | MPASS((tp->t_hook == NULL) == ((tp->t_flags & TF_HOOK) == 0)); |
| 2130 | if (tp->t_flags & TF_HOOK) |
| 2131 | goto done3; |
| 2132 | |
| 2133 | tp->t_flags |= TF_HOOK; |
no test coverage detected