1/* $NetBSD: linux32_termios.c,v 1.16 2021/11/26 19:28:37 ryo Exp $ */ 2 3/*- 4 * Copyright (c) 1995-2006, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden, Eric Haszlakiewicz, and Emmanuel Dreyfus. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: linux32_termios.c,v 1.16 2021/11/26 19:28:37 ryo Exp $"); 34 35#ifdef _KERNEL_OPT 36#include "opt_compat_linux32.h" 37#include "opt_ptm.h" 38#endif 39 40#include <sys/param.h> 41#include <sys/proc.h> 42#include <sys/systm.h> 43#include <sys/file.h> 44#include <sys/filedesc.h> 45#include <sys/ioctl.h> 46#include <sys/mount.h> 47#include <sys/termios.h> 48#include <sys/kernel.h> 49 50#include <compat/netbsd32/netbsd32.h> 51#include <compat/netbsd32/netbsd32_syscallargs.h> 52 53#include <compat/linux32/common/linux32_types.h> 54#include <compat/linux32/common/linux32_signal.h> 55#include <compat/linux32/common/linux32_ioctl.h> 56#include <compat/linux32/common/linux32_machdep.h> 57#include <compat/linux32/common/linux32_termios.h> 58#include <compat/linux32/linux32_syscallargs.h> 59 60#include <compat/linux/common/linux_types.h> 61#include <compat/linux/common/linux_signal.h> 62#include <compat/linux/common/linux_util.h> 63#include <compat/linux/common/linux_termios.h> 64#include <compat/linux/common/linux_ipc.h> 65#include <compat/linux/common/linux_sem.h> 66 67#include <compat/linux/linux_syscallargs.h> 68 69#ifdef DEBUG_LINUX 70#define DPRINTF(a) uprintf a 71#else 72#define DPRINTF(a) 73#endif 74 75int 76linux32_ioctl_termios(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) 77{ 78 /* { 79 syscallarg(int) fd; 80 syscallarg(netbsd32_u_long) com; 81 syscallarg(netbsd32_charp) data; 82 } */ 83 file_t *fp; 84 u_long com; 85 struct linux32_termio tmplt; 86 struct linux32_termios tmplts; 87 struct termios tmpbts; 88 int idat; 89 struct netbsd32_ioctl_args ia; 90 int error; 91 char tioclinux; 92 int (*bsdioctl)(file_t *, u_long, void *); 93 94 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) 95 return (EBADF); 96 97 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 98 error = EBADF; 99 goto out; 100 } 101 102 bsdioctl = fp->f_ops->fo_ioctl; 103 com = SCARG(uap, com); 104 retval[0] = 0; 105 106 switch (com) { 107 case LINUX32_TCGETS: 108 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 109 if (error) 110 goto out; 111 bsd_termios_to_linux32_termios(&tmpbts, &tmplts); 112 error = copyout(&tmplts, SCARG_P32(uap, data), sizeof tmplts); 113 goto out; 114 case LINUX32_TCSETS: 115 case LINUX32_TCSETSW: 116 case LINUX32_TCSETSF: 117 /* 118 * First fill in all fields, so that we keep the current 119 * values for fields that Linux doesn't know about. 120 */ 121 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 122 if (error) 123 goto out; 124 if ((error = copyin(SCARG_P32(uap, data), 125 &tmplts, sizeof tmplts)) != 0) 126 goto out; 127 linux32_termios_to_bsd_termios(&tmplts, &tmpbts); 128 switch (com) { 129 case LINUX32_TCSETS: 130 com = TIOCSETA; 131 break; 132 case LINUX32_TCSETSW: 133 com = TIOCSETAW; 134 break; 135 case LINUX32_TCSETSF: 136 com = TIOCSETAF; 137 break; 138 } 139 error = (*bsdioctl)(fp, com, &tmpbts); 140 goto out; 141 case LINUX32_TCGETA: 142 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 143 if (error) 144 goto out; 145 bsd_termios_to_linux32_termio(&tmpbts, &tmplt); 146 error = copyout(&tmplt, SCARG_P32(uap, data), sizeof tmplt); 147 goto out; 148 case LINUX32_TCSETA: 149 case LINUX32_TCSETAW: 150 case LINUX32_TCSETAF: 151 /* 152 * First fill in all fields, so that we keep the current 153 * values for fields that Linux doesn't know about. 154 */ 155 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 156 if (error) 157 goto out; 158 if ((error = copyin(SCARG_P32(uap, data), 159 &tmplt, sizeof tmplt)) != 0) 160 goto out; 161 linux32_termio_to_bsd_termios(&tmplt, &tmpbts); 162 switch (com) { 163 case LINUX32_TCSETA: 164 com = TIOCSETA; 165 break; 166 case LINUX32_TCSETAW: 167 com = TIOCSETAW; 168 break; 169 case LINUX32_TCSETAF: 170 com = TIOCSETAF; 171 break; 172 } 173 error = (*bsdioctl)(fp, com, &tmpbts); 174 goto out; 175 case LINUX32_TCFLSH: 176 switch((u_long)SCARG_P32(uap, data)) { 177 case 0: 178 idat = FREAD; 179 break; 180 case 1: 181 idat = FWRITE; 182 break; 183 case 2: 184 idat = 0; 185 break; 186 default: 187 error = EINVAL; 188 goto out; 189 } 190 error = (*bsdioctl)(fp, TIOCFLUSH, &idat); 191 goto out; 192 case LINUX32_TIOCGETD: 193 error = (*bsdioctl)(fp, TIOCGETD, &idat); 194 if (error) 195 goto out; 196 switch (idat) { 197 case TTYDISC: 198 idat = LINUX_N_TTY; 199 break; 200 case SLIPDISC: 201 idat = LINUX_N_SLIP; 202 break; 203 case PPPDISC: 204 idat = LINUX_N_PPP; 205 break; 206 case STRIPDISC: 207 idat = LINUX_N_STRIP; 208 break; 209 /* 210 * Linux does not have the tablet line discipline. 211 */ 212 case TABLDISC: 213 default: 214 idat = -1; /* XXX What should this be? */ 215 break; 216 } 217 error = copyout(&idat, SCARG_P32(uap, data), sizeof idat); 218 goto out; 219 case LINUX32_TIOCSETD: 220 if ((error = copyin(SCARG_P32(uap, data), 221 &idat, sizeof idat)) != 0) 222 goto out; 223 switch (idat) { 224 case LINUX_N_TTY: 225 idat = TTYDISC; 226 break; 227 case LINUX_N_SLIP: 228 idat = SLIPDISC; 229 break; 230 case LINUX_N_PPP: 231 idat = PPPDISC; 232 break; 233 case LINUX_N_STRIP: 234 idat = STRIPDISC; 235 break; 236 /* 237 * We can't handle the mouse line discipline Linux has. 238 */ 239 case LINUX_N_MOUSE: 240 case LINUX_N_AX25: 241 case LINUX_N_X25: 242 case LINUX_N_6PACK: 243 default: 244 error = EINVAL; 245 goto out; 246 } 247 error = (*bsdioctl)(fp, TIOCSETD, &idat); 248 goto out; 249 case LINUX32_TIOCLINUX: 250 if ((error = copyin(SCARG_P32(uap, data), 251 &tioclinux, sizeof tioclinux)) != 0) 252 goto out; 253 switch (tioclinux) { 254 case LINUX_TIOCLINUX_KERNMSG: 255 /* 256 * XXX needed to not fail for some things. Could 257 * try to use TIOCCONS, but the char argument 258 * specifies the VT #, not an fd. 259 */ 260 error = 0; 261 goto out; 262 case LINUX_TIOCLINUX_COPY: 263 case LINUX_TIOCLINUX_PASTE: 264 case LINUX_TIOCLINUX_UNBLANK: 265 case LINUX_TIOCLINUX_LOADLUT: 266 case LINUX_TIOCLINUX_READSHIFT: 267 case LINUX_TIOCLINUX_READMOUSE: 268 case LINUX_TIOCLINUX_VESABLANK: 269 case LINUX_TIOCLINUX_CURCONS: /* could use VT_GETACTIVE */ 270 default: 271 error = EINVAL; 272 goto out; 273 } 274 break; 275 case LINUX32_TIOCGWINSZ: 276 SCARG(&ia, com) = TIOCGWINSZ; 277 break; 278 case LINUX32_TIOCSWINSZ: 279 SCARG(&ia, com) = TIOCSWINSZ; 280 break; 281 case LINUX32_TIOCGPGRP: 282 SCARG(&ia, com) = TIOCGPGRP; 283 break; 284 case LINUX32_TIOCSPGRP: 285 SCARG(&ia, com) = TIOCSPGRP; 286 break; 287 case LINUX32_FIOCLEX: 288 SCARG(&ia, com) = FIOCLEX; 289 break; 290 case LINUX32_FIONCLEX: 291 SCARG(&ia, com) = FIONCLEX; 292 break; 293 case LINUX32_FIONREAD: 294 SCARG(&ia, com) = FIONREAD; 295 break; 296 case LINUX32_FIONBIO: 297 SCARG(&ia, com) = FIONBIO; 298 break; 299 case LINUX32_FIOASYNC: 300 SCARG(&ia, com) = FIOASYNC; 301 break; 302 case LINUX32_TIOCEXCL: 303 SCARG(&ia, com) = TIOCEXCL; 304 break; 305 case LINUX32_TIOCNXCL: 306 SCARG(&ia, com) = TIOCNXCL; 307 break; 308 case LINUX32_TIOCCONS: 309 SCARG(&ia, com) = TIOCCONS; 310 break; 311 case LINUX32_TIOCNOTTY: 312 SCARG(&ia, com) = TIOCNOTTY; 313 break; 314 case LINUX32_TCSBRK: 315 idat = (u_long)SCARG_P32(uap, data); 316 if (idat != 0) 317 SCARG(&ia, com) = TIOCDRAIN; 318 else { 319 if ((error = (*bsdioctl)(fp, TIOCSBRK, NULL)) != 0) 320 goto out; 321 error = tsleep(&idat, PZERO | PCATCH, "linux_tcsbrk", hz / 4); 322 if (error == EINTR || error == ERESTART) { 323 (void)(*bsdioctl)(fp, TIOCCBRK, NULL); 324 error = EINTR; 325 } else 326 error = (*bsdioctl)(fp, TIOCCBRK, NULL); 327 goto out; 328 } 329 break; 330 case LINUX32_TIOCMGET: 331 SCARG(&ia, com) = TIOCMGET; 332 break; 333 case LINUX32_TIOCMSET: 334 SCARG(&ia, com) = TIOCMSET; 335 break; 336 case LINUX32_TIOCMBIC: 337 SCARG(&ia, com) = TIOCMBIC; 338 break; 339 case LINUX32_TIOCMBIS: 340 SCARG(&ia, com) = TIOCMBIS; 341 break; 342#ifdef LINUX32_TIOCGPTN 343 case LINUX32_TIOCGPTN: 344#ifndef NO_DEV_PTM 345 { 346 struct ptmget ptm; 347 348 error = (*bsdioctl)(fp, TIOCPTSNAME, &ptm); 349 if (error != 0) 350 goto out; 351 352 error = copyout(&ptm.sfd, SCARG_P32(uap, data), 353 sizeof(ptm.sfd)); 354 goto out; 355 } 356#endif /* NO_DEV_PTM */ 357#endif /* LINUX32_TIOCGPTN */ 358#ifdef LINUX32_TIOCSPTLCK 359 case LINUX32_TIOCSPTLCK: 360 fd_putfile(SCARG(uap, fd)); 361 error = copyin(SCARG_P32(uap, data), &idat, sizeof(idat)); 362 if (error) 363 return error; 364 DPRINTF(("TIOCSPTLCK %d\n", idat)); 365 return 0; 366#endif 367 case LINUX32_TCXONC: 368 idat = (u_long)SCARG_P32(uap, data); 369 switch (idat) { 370 case LINUX_TCOOFF: 371 SCARG(&ia, com) = TIOCSTOP; 372 break; 373 case LINUX_TCOON: 374 SCARG(&ia, com) = TIOCSTART; 375 break; 376 case LINUX_TCIOFF: 377 case LINUX_TCION: 378 default: 379 error = EINVAL; 380 goto out; 381 } 382 break; 383 default: 384 error = EINVAL; 385 goto out; 386 } 387 388 SCARG(&ia, fd) = SCARG(uap, fd); 389 SCARG(&ia, data) = SCARG(uap, data); 390 error = netbsd32_ioctl(curlwp, &ia, retval); 391out: 392 fd_putfile(SCARG(uap, fd)); 393 return error; 394} 395