1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 /* 41 * Module to intercept old V7 and 4BSD "ioctl" calls. 42 */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/signal.h> 47 #include <sys/file.h> 48 #include <sys/termios.h> 49 #include <sys/ttold.h> 50 #include <sys/cmn_err.h> 51 #include <sys/stream.h> 52 #include <sys/stropts.h> 53 #include <sys/strsubr.h> 54 #include <sys/strsun.h> 55 #include <sys/errno.h> 56 #include <sys/debug.h> 57 #include <sys/ttcompat.h> 58 #include <sys/ddi.h> 59 #include <sys/sunddi.h> 60 #include <sys/kmem.h> 61 #include <sys/policy.h> 62 63 /* 64 * This is the loadable module wrapper. 65 */ 66 #include <sys/conf.h> 67 #include <sys/modctl.h> 68 69 /* See os/streamio.c */ 70 extern int sgttyb_handling; 71 72 static struct streamtab ttcoinfo; 73 74 static struct fmodsw fsw = { 75 "ttcompat", 76 &ttcoinfo, 77 D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE 78 }; 79 80 /* 81 * Module linkage information for the kernel. 82 */ 83 84 static struct modlstrmod modlstrmod = { 85 &mod_strmodops, 86 "alt ioctl calls", 87 &fsw 88 }; 89 90 static struct modlinkage modlinkage = { 91 MODREV_1, &modlstrmod, NULL 92 }; 93 94 int 95 _init(void) 96 { 97 return (mod_install(&modlinkage)); 98 } 99 100 int 101 _fini(void) 102 { 103 return (mod_remove(&modlinkage)); 104 } 105 106 int 107 _info(struct modinfo *modinfop) 108 { 109 return (mod_info(&modlinkage, modinfop)); 110 } 111 112 static int ttcompatopen(queue_t *, dev_t *, int, int, cred_t *); 113 static int ttcompatclose(queue_t *, int, cred_t *); 114 static void ttcompatrput(queue_t *, mblk_t *); 115 static void ttcompatwput(queue_t *, mblk_t *); 116 117 static struct module_info ttycompatmiinfo = { 118 0, 119 "ttcompat", 120 0, 121 INFPSZ, 122 2048, 123 128 124 }; 125 126 static struct qinit ttycompatrinit = { 127 (int (*)())ttcompatrput, 128 NULL, 129 ttcompatopen, 130 ttcompatclose, 131 NULL, 132 &ttycompatmiinfo 133 }; 134 135 static struct module_info ttycompatmoinfo = { 136 42, 137 "ttcompat", 138 0, 139 INFPSZ, 140 300, 141 200 142 }; 143 144 static struct qinit ttycompatwinit = { 145 (int (*)())ttcompatwput, 146 NULL, 147 ttcompatopen, 148 ttcompatclose, 149 NULL, 150 &ttycompatmoinfo 151 }; 152 153 static struct streamtab ttcoinfo = { 154 &ttycompatrinit, 155 &ttycompatwinit, 156 NULL, 157 NULL 158 }; 159 160 /* 161 * This is the termios structure that is used to reset terminal settings 162 * when the underlying device is an instance of zcons. It came from 163 * cmd/init/init.c and should be kept in-sync with dflt_termios found therein. 164 */ 165 static const struct termios base_termios = { 166 BRKINT|ICRNL|IXON|IMAXBEL, /* iflag */ 167 OPOST|ONLCR|TAB3, /* oflag */ 168 CS8|CREAD|B9600, /* cflag */ 169 ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN, /* lflag */ 170 CINTR, CQUIT, CERASE, CKILL, CEOF, 0, 0, 0, 0, 0, 0, 0, /* c_cc vals */ 171 0, 0, 0, 0, 0, 0, 0 172 }; 173 174 175 static void ttcompat_do_ioctl(ttcompat_state_t *, queue_t *, mblk_t *); 176 static void ttcompat_ioctl_ack(queue_t *, mblk_t *); 177 static void ttcopyout(queue_t *, mblk_t *); 178 static void ttcompat_ioctl_nak(queue_t *, mblk_t *); 179 static void from_compat(compat_state_t *, struct termios *); 180 static void to_compat(struct termios *, compat_state_t *); 181 182 /* 183 * Open - get the current modes and translate them to the V7/4BSD equivalent. 184 */ 185 /*ARGSUSED*/ 186 static int 187 ttcompatopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) 188 { 189 ttcompat_state_t *tp; 190 mblk_t *mp; 191 mblk_t *datamp; 192 struct iocblk *iocb; 193 int error; 194 195 if (q->q_ptr != NULL) { 196 tp = (ttcompat_state_t *)q->q_ptr; 197 /* fail open if TIOCEXCL was done and its not privileged */ 198 if ((tp->t_new_lflags & XCLUDE) && 199 secpolicy_excl_open(crp) != 0) { 200 return (EBUSY); 201 } 202 return (0); /* already attached */ 203 } 204 tp = kmem_zalloc(sizeof (ttcompat_state_t), KM_SLEEP); 205 tp->t_iocpending = NULL; 206 tp->t_state = 0; 207 tp->t_iocid = 0; 208 tp->t_ioccmd = 0; 209 tp->t_new_lflags = 0; 210 tp->t_curstate.t_flags = 0; 211 tp->t_curstate.t_ispeed = B0; 212 tp->t_curstate.t_ospeed = B0; 213 tp->t_curstate.t_erase = '\0'; 214 tp->t_curstate.t_kill = '\0'; 215 tp->t_curstate.t_intrc = '\0'; 216 tp->t_curstate.t_quitc = '\0'; 217 tp->t_curstate.t_startc = '\0'; 218 tp->t_curstate.t_stopc = '\0'; 219 tp->t_curstate.t_eofc = '\0'; 220 tp->t_curstate.t_brkc = '\0'; 221 tp->t_curstate.t_suspc = '\0'; 222 tp->t_curstate.t_dsuspc = '\0'; 223 tp->t_curstate.t_rprntc = '\0'; 224 tp->t_curstate.t_flushc = '\0'; 225 tp->t_curstate.t_werasc = '\0'; 226 tp->t_curstate.t_lnextc = '\0'; 227 tp->t_curstate.t_xflags = 0; 228 tp->t_bufcallid = 0; 229 tp->t_arg = 0; 230 231 q->q_ptr = tp; 232 WR(q)->q_ptr = tp; 233 qprocson(q); 234 235 /* 236 * Determine if the underlying device is a zcons instance. If so, 237 * then issue a termios ioctl to reset the terminal settings. 238 */ 239 if (getmajor(q->q_stream->sd_vnode->v_rdev) != 240 ddi_name_to_major("zcons")) 241 return (0); 242 243 /* 244 * Create the ioctl message. 245 */ 246 if ((mp = mkiocb(TCSETSF)) == NULL) { 247 error = ENOMEM; 248 goto common_error; 249 } 250 if ((datamp = allocb(sizeof (struct termios), BPRI_HI)) == NULL) { 251 freemsg(mp); 252 error = ENOMEM; 253 goto common_error; 254 } 255 iocb = (struct iocblk *)mp->b_rptr; 256 iocb->ioc_count = sizeof (struct termios); 257 bcopy(&base_termios, datamp->b_rptr, sizeof (struct termios)); 258 datamp->b_wptr += sizeof (struct termios); 259 mp->b_cont = datamp; 260 261 /* 262 * Send the ioctl message on its merry way toward the driver. 263 * Set some state beforehand so we can properly wait for 264 * an acknowledgement. 265 */ 266 tp->t_state |= TS_IOCWAIT | TS_TIOCNAK; 267 tp->t_iocid = iocb->ioc_id; 268 tp->t_ioccmd = TCSETSF; 269 putnext(WR(q), mp); 270 271 /* 272 * Wait for an acknowledgement. A NAK is treated as an error. 273 * The presence of the TS_TIOCNAK flag indicates that a NAK was 274 * received. 275 */ 276 while (tp->t_state & TS_IOCWAIT) { 277 if (qwait_sig(q) == 0) { 278 error = EINTR; 279 goto common_error; 280 } 281 } 282 if (!(tp->t_state & TS_TIOCNAK)) 283 return (0); 284 error = ENOTTY; 285 286 common_error: 287 qprocsoff(q); 288 kmem_free(tp, sizeof (ttcompat_state_t)); 289 q->q_ptr = NULL; 290 WR(q)->q_ptr = NULL; 291 return (error); 292 } 293 294 /* ARGSUSED1 */ 295 static int 296 ttcompatclose(queue_t *q, int flag, cred_t *crp) 297 { 298 ttcompat_state_t *tp = (ttcompat_state_t *)q->q_ptr; 299 mblk_t *mp; 300 301 /* Dump the state structure, then unlink it */ 302 qprocsoff(q); 303 if (tp->t_bufcallid != 0) { 304 qunbufcall(q, tp->t_bufcallid); 305 tp->t_bufcallid = 0; 306 } 307 if ((mp = tp->t_iocpending) != NULL) 308 freemsg(mp); 309 kmem_free(tp, sizeof (ttcompat_state_t)); 310 q->q_ptr = NULL; 311 312 return (0); 313 } 314 315 /* 316 * Put procedure for input from driver end of stream (read queue). 317 * Most messages just get passed to the next guy up; we intercept 318 * "ioctl" replies, and if it's an "ioctl" whose reply we plan to do 319 * something with, we do it. 320 */ 321 static void 322 ttcompatrput(queue_t *q, mblk_t *mp) 323 { 324 switch (mp->b_datap->db_type) { 325 326 case M_IOCACK: 327 ttcompat_ioctl_ack(q, mp); 328 break; 329 330 case M_IOCNAK: 331 ttcompat_ioctl_nak(q, mp); 332 break; 333 334 default: 335 putnext(q, mp); 336 break; 337 } 338 } 339 340 /* 341 * Line discipline output queue put procedure: speeds M_IOCTL 342 * messages. 343 */ 344 static void 345 ttcompatwput(queue_t *q, mblk_t *mp) 346 { 347 ttcompat_state_t *tp; 348 struct copyreq *cqp; 349 struct copyresp *csp; 350 struct iocblk *iocbp; 351 352 tp = (ttcompat_state_t *)q->q_ptr; 353 354 /* 355 * Process some M_IOCTL messages here; pass everything else down. 356 */ 357 switch (mp->b_datap->db_type) { 358 359 default: 360 putnext(q, mp); 361 return; 362 363 case M_IOCTL: 364 iocbp = (struct iocblk *)mp->b_rptr; 365 366 switch (iocbp->ioc_cmd) { 367 368 default: 369 /* these are ioctls with no arguments or are known to stream head */ 370 /* process them right away */ 371 ttcompat_do_ioctl(tp, q, mp); 372 return; 373 case TIOCSETN: 374 case TIOCSLTC: 375 case TIOCSETC: 376 case TIOCLBIS: 377 case TIOCLBIC: 378 case TIOCLSET: 379 case TIOCFLUSH: 380 if (iocbp->ioc_count != TRANSPARENT) { 381 putnext(q, mp); 382 return; 383 } 384 385 mp->b_datap->db_type = M_COPYIN; 386 cqp = (struct copyreq *)mp->b_rptr; 387 cqp->cq_addr = (caddr_t)*(intptr_t *)mp->b_cont->b_rptr; 388 switch (iocbp->ioc_cmd) { 389 case TIOCSETN: 390 cqp->cq_size = sizeof (struct sgttyb); 391 break; 392 case TIOCSLTC: 393 cqp->cq_size = sizeof (struct ltchars); 394 break; 395 case TIOCSETC: 396 cqp->cq_size = sizeof (struct tchars); 397 break; 398 case TIOCLBIS: 399 case TIOCLBIC: 400 case TIOCLSET: 401 case TIOCFLUSH: 402 cqp->cq_size = sizeof (int); 403 break; 404 default: 405 break; 406 } 407 cqp->cq_flag = 0; 408 cqp->cq_private = NULL; 409 freemsg(mp->b_cont); 410 mp->b_cont = NULL; 411 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 412 tp->t_ioccmd = iocbp->ioc_cmd; 413 tp->t_state |= TS_W_IN; 414 qreply(q, mp); 415 return; 416 417 } /* switch ioc_cmd */ 418 case M_IOCDATA: 419 csp = (struct copyresp *)mp->b_rptr; 420 421 switch (csp->cp_cmd) { 422 423 default: 424 putnext(q, mp); 425 return; 426 427 case TIOCSETN: 428 case TIOCSLTC: 429 case TIOCSETC: 430 case TIOCLBIS: 431 case TIOCLBIC: 432 case TIOCLSET: 433 case TIOCFLUSH: 434 tp->t_state &= ~TS_W_IN; 435 if (csp->cp_rval != 0) { /* failure */ 436 freemsg(mp); 437 return; 438 } 439 440 /* make it look like an ioctl */ 441 mp->b_datap->db_type = M_IOCTL; 442 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 443 iocbp = (struct iocblk *)mp->b_rptr; 444 iocbp->ioc_count = MBLKL(mp->b_cont); 445 iocbp->ioc_error = 0; 446 iocbp->ioc_rval = 0; 447 ttcompat_do_ioctl(tp, q, mp); 448 return; 449 450 case TIOCGLTC: 451 case TIOCLGET: 452 case TIOCGETC: 453 tp->t_state &= ~TS_W_OUT; 454 if (csp->cp_rval != 0) { /* failure */ 455 freemsg(mp); 456 return; 457 } 458 459 iocbp = (struct iocblk *)mp->b_rptr; 460 iocbp->ioc_count = 0; 461 iocbp->ioc_error = 0; 462 iocbp->ioc_rval = 0; 463 mp->b_datap->db_type = M_IOCACK; 464 qreply(q, mp); 465 return; 466 467 } /* switch cp_cmd */ 468 } /* end message switch */ 469 } 470 471 /* 472 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 473 * the buffer we need. 474 */ 475 static void 476 ttcompat_reioctl(void *arg) 477 { 478 queue_t *q = arg; 479 ttcompat_state_t *tp; 480 mblk_t *mp; 481 482 tp = (ttcompat_state_t *)q->q_ptr; 483 tp->t_bufcallid = 0; 484 485 if ((mp = tp->t_iocpending) != NULL) { 486 tp->t_iocpending = NULL; /* not pending any more */ 487 ttcompat_do_ioctl(tp, q, mp); 488 } 489 } 490 491 /* 492 * Handle old-style "ioctl" messages; pass the rest down unmolested. 493 */ 494 static void 495 ttcompat_do_ioctl(ttcompat_state_t *tp, queue_t *q, mblk_t *mp) 496 { 497 struct iocblk *iocp; 498 int error; 499 500 /* 501 * Most of the miocpullup()'s below aren't needed because the 502 * ioctls in question are actually transparent M_IOCDATA messages 503 * dummied to look like M_IOCTL messages. However, for clarity and 504 * robustness against future changes, we've included them anyway. 505 */ 506 507 iocp = (struct iocblk *)mp->b_rptr; 508 switch (iocp->ioc_cmd) { 509 510 /* 511 * "get"-style calls that get translated data from the "termios" 512 * structure. Save the existing code and pass it down as a TCGETS. 513 */ 514 case TIOCGETC: 515 case TIOCLGET: 516 case TIOCGLTC: 517 if (iocp->ioc_count != TRANSPARENT) { 518 miocnak(q, mp, 0, EINVAL); 519 return; 520 } 521 522 /* 523 * We can get here with t_arg != 0, iff the stream head 524 * has for some reason given up on the ioctl in progress. 525 * The most likely cause is an interrupted ioctl syscall. 526 * We will behave robustly because (given our perimeter) 527 * the ttcompat_state_t will get set up for the new ioctl, 528 * and when the response we were waiting for appears it 529 * will be passed on to the stream head which will discard 530 * it as non-current. 531 */ 532 ASSERT(mp->b_cont != NULL); 533 tp->t_arg = *(intptr_t *)mp->b_cont->b_rptr; 534 /* free the data buffer - it might not be sufficient */ 535 /* driver will allocate one for termios size */ 536 freemsg(mp->b_cont); 537 mp->b_cont = NULL; 538 iocp->ioc_count = 0; 539 /* FALLTHRU */ 540 case TIOCGETP: 541 goto dogets; 542 543 /* 544 * "set"-style calls that set translated data into a "termios" 545 * structure. Set our idea of the new state from the value 546 * given to us. We then have to get the current state, so we 547 * turn this guy into a TCGETS and pass it down. When the 548 * ACK comes back, we modify the state we got back and shove it 549 * back down as the appropriate type of TCSETS. 550 */ 551 case TIOCSETP: 552 case TIOCSETN: 553 error = miocpullup(mp, sizeof (struct sgttyb)); 554 if (error != 0) { 555 miocnak(q, mp, 0, error); 556 return; 557 } 558 tp->t_new_sgttyb = *((struct sgttyb *)mp->b_cont->b_rptr); 559 goto dogets; 560 561 case TIOCSETC: 562 error = miocpullup(mp, sizeof (struct tchars)); 563 if (error != 0) { 564 miocnak(q, mp, 0, error); 565 return; 566 } 567 tp->t_new_tchars = *((struct tchars *)mp->b_cont->b_rptr); 568 goto dogets; 569 570 case TIOCSLTC: 571 error = miocpullup(mp, sizeof (struct ltchars)); 572 if (error != 0) { 573 miocnak(q, mp, 0, error); 574 return; 575 } 576 tp->t_new_ltchars = *((struct ltchars *)mp->b_cont->b_rptr); 577 goto dogets; 578 579 case TIOCLBIS: 580 case TIOCLBIC: 581 case TIOCLSET: 582 error = miocpullup(mp, sizeof (int)); 583 if (error != 0) { 584 miocnak(q, mp, 0, error); 585 return; 586 } 587 tp->t_new_lflags = *(int *)mp->b_cont->b_rptr; 588 goto dogets; 589 590 /* 591 * "set"-style call that sets a particular bit in a "termios" 592 * structure. We then have to get the current state, so we 593 * turn this guy into a TCGETS and pass it down. When the 594 * ACK comes back, we modify the state we got back and shove it 595 * back down as the appropriate type of TCSETS. 596 */ 597 case TIOCHPCL: 598 dogets: 599 tp->t_ioccmd = iocp->ioc_cmd; 600 tp->t_iocid = iocp->ioc_id; 601 tp->t_state |= TS_IOCWAIT; 602 iocp->ioc_cmd = TCGETS; 603 iocp->ioc_count = 0; /* no data returned unless we say so */ 604 break; 605 606 /* 607 * "set"-style call that sets DTR. Pretend that it was a TIOCMBIS 608 * with TIOCM_DTR set. 609 */ 610 case TIOCSDTR: { 611 mblk_t *datap; 612 613 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 614 goto allocfailure; 615 *(int *)datap->b_wptr = TIOCM_DTR; 616 datap->b_wptr += sizeof (int); 617 iocp->ioc_cmd = TIOCMBIS; /* turn it into a TIOCMBIS */ 618 if (mp->b_cont != NULL) 619 freemsg(mp->b_cont); 620 mp->b_cont = datap; /* attach the data */ 621 iocp->ioc_count = sizeof (int); /* in case driver checks */ 622 break; 623 } 624 625 /* 626 * "set"-style call that clears DTR. Pretend that it was a TIOCMBIC 627 * with TIOCM_DTR set. 628 */ 629 case TIOCCDTR: { 630 mblk_t *datap; 631 632 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 633 goto allocfailure; 634 *(int *)datap->b_wptr = TIOCM_DTR; 635 datap->b_wptr += sizeof (int); 636 iocp->ioc_cmd = TIOCMBIC; /* turn it into a TIOCMBIC */ 637 if (mp->b_cont != NULL) 638 freemsg(mp->b_cont); 639 mp->b_cont = datap; /* attach the data */ 640 iocp->ioc_count = sizeof (int); /* in case driver checks */ 641 break; 642 } 643 644 /* 645 * Translate into the S5 form of TCFLSH. 646 */ 647 case TIOCFLUSH: { 648 int flags; 649 650 error = miocpullup(mp, sizeof (int)); 651 if (error != 0) { 652 miocnak(q, mp, 0, error); 653 return; 654 } 655 flags = *(int *)mp->b_cont->b_rptr; 656 657 switch (flags&(FREAD|FWRITE)) { 658 659 case 0: 660 case FREAD|FWRITE: 661 flags = 2; /* flush 'em both */ 662 break; 663 664 case FREAD: 665 flags = 0; /* flush read */ 666 break; 667 668 case FWRITE: 669 flags = 1; /* flush write */ 670 break; 671 } 672 iocp->ioc_cmd = TCFLSH; /* turn it into a TCFLSH */ 673 *(int *)mp->b_cont->b_rptr = flags; /* fiddle the arg */ 674 break; 675 } 676 677 /* 678 * Turn into a TCXONC. 679 */ 680 case TIOCSTOP: { 681 mblk_t *datap; 682 683 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 684 goto allocfailure; 685 *(int *)datap->b_wptr = 0; /* stop */ 686 datap->b_wptr += sizeof (int); 687 iocp->ioc_cmd = TCXONC; /* turn it into a XONC */ 688 iocp->ioc_count = sizeof (int); 689 if (mp->b_cont != NULL) 690 freemsg(mp->b_cont); 691 mp->b_cont = datap; /* attach the data */ 692 break; 693 } 694 695 case TIOCSTART: { 696 mblk_t *datap; 697 698 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) 699 goto allocfailure; 700 *(int *)datap->b_wptr = 1; /* start */ 701 datap->b_wptr += sizeof (int); 702 iocp->ioc_cmd = TCXONC; /* turn it into a XONC */ 703 iocp->ioc_count = sizeof (int); 704 if (mp->b_cont != NULL) 705 freemsg(mp->b_cont); 706 mp->b_cont = datap; /* attach the data */ 707 break; 708 } 709 case TIOCSETD: 710 case TIOCGETD: 711 case DIOCSETP: 712 case DIOCGETP: 713 case LDOPEN: 714 case LDCLOSE: 715 case LDCHG: 716 case LDSETT: 717 case LDGETT: 718 /* 719 * All of these ioctls are just ACK'd, except for 720 * TIOCSETD, which must be for line discipline zero. 721 */ 722 mp->b_datap->db_type = M_IOCACK; 723 if (iocp->ioc_cmd == TIOCSETD) { 724 iocp->ioc_error = miocpullup(mp, sizeof (uchar_t)); 725 if (iocp->ioc_error == 0 && (*mp->b_cont->b_rptr != 0)) 726 mp->b_datap->db_type = M_IOCNAK; 727 } 728 729 iocp->ioc_error = 0; 730 iocp->ioc_count = 0; 731 iocp->ioc_rval = 0; 732 qreply(q, mp); 733 return; 734 case IOCTYPE: 735 mp->b_datap->db_type = M_IOCACK; 736 iocp->ioc_error = 0; 737 iocp->ioc_count = 0; 738 iocp->ioc_rval = TIOC; 739 qreply(q, mp); 740 return; 741 case TIOCEXCL: 742 /* check for binary value of XCLUDE flag ???? */ 743 tp->t_new_lflags |= XCLUDE; 744 mp->b_datap->db_type = M_IOCACK; 745 iocp->ioc_error = 0; 746 iocp->ioc_count = 0; 747 iocp->ioc_rval = 0; 748 qreply(q, mp); 749 return; 750 case TIOCNXCL: 751 tp->t_new_lflags &= ~XCLUDE; 752 mp->b_datap->db_type = M_IOCACK; 753 iocp->ioc_error = 0; 754 iocp->ioc_count = 0; 755 iocp->ioc_rval = 0; 756 qreply(q, mp); 757 return; 758 } 759 760 /* 761 * We don't reply to most calls, we just pass them down, 762 * possibly after modifying the arguments. 763 */ 764 putnext(q, mp); 765 return; 766 767 allocfailure: 768 /* 769 * We needed to allocate something to handle this "ioctl", but 770 * couldn't; save this "ioctl" and arrange to get called back when 771 * it's more likely that we can get what we need. 772 * If there's already one being saved, throw it out, since it 773 * must have timed out. 774 */ 775 if (tp->t_iocpending != NULL) 776 freemsg(tp->t_iocpending); 777 tp->t_iocpending = mp; /* hold this ioctl */ 778 if (tp->t_bufcallid != 0) 779 qunbufcall(q, tp->t_bufcallid); 780 781 tp->t_bufcallid = qbufcall(q, sizeof (struct iocblk), BPRI_HI, 782 ttcompat_reioctl, q); 783 } 784 785 /* 786 * Called when an M_IOCACK message is seen on the read queue; if this 787 * is the response we were waiting for, we either: 788 * modify the data going up (if the "ioctl" read data); since in all 789 * cases, the old-style returned information is smaller than or the same 790 * size as the new-style returned information, we just overwrite the old 791 * stuff with the new stuff (beware of changing structure sizes, in case 792 * you invalidate this) 793 * or 794 * take this data, modify it appropriately, and send it back down (if 795 * the "ioctl" wrote data). 796 * In either case, we cancel the "wait"; the final response to a "write" 797 * ioctl goes back up to the user. 798 * If this wasn't the response we were waiting for, just pass it up. 799 */ 800 static void 801 ttcompat_ioctl_ack(queue_t *q, mblk_t *mp) 802 { 803 ttcompat_state_t *tp; 804 struct iocblk *iocp; 805 mblk_t *datap; 806 807 tp = (ttcompat_state_t *)q->q_ptr; 808 iocp = (struct iocblk *)mp->b_rptr; 809 810 if (!(tp->t_state&TS_IOCWAIT) || iocp->ioc_id != tp->t_iocid) { 811 /* 812 * This isn't the reply we're looking for. Move along. 813 */ 814 putnext(q, mp); 815 return; 816 } 817 818 datap = mp->b_cont; /* mblk containing data going up */ 819 820 switch (tp->t_ioccmd) { 821 822 case TIOCGETP: { 823 struct sgttyb *cb; 824 825 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 826 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 827 /* recycle the reply's buffer */ 828 cb = (struct sgttyb *)datap->b_wptr; 829 /* 830 * This is used for TIOCGETP handling of sg_ispeed and 831 * sg_ospeed. If the current speed is over 38400 (the 832 * sgttyb limit), then we report 38400. Note that 833 * when "compatibility with old releases" is enabled 834 * (sgttyb_handling == 0), then t_[io]speed will have 835 * garbled nonsense, as in prior releases. (See 836 * to_compat() below). 837 */ 838 cb->sg_ispeed = tp->t_curstate.t_ispeed > B38400 ? B38400 : 839 tp->t_curstate.t_ispeed; 840 cb->sg_ospeed = tp->t_curstate.t_ospeed > B38400 ? B38400 : 841 tp->t_curstate.t_ospeed; 842 cb->sg_erase = tp->t_curstate.t_erase; 843 cb->sg_kill = tp->t_curstate.t_kill; 844 cb->sg_flags = tp->t_curstate.t_flags; 845 datap->b_wptr += sizeof (struct sgttyb); 846 iocp->ioc_count = sizeof (struct sgttyb); 847 848 /* you are lucky - stream head knows how to copy you out */ 849 850 tp->t_state &= ~TS_IOCWAIT; /* we got what we wanted */ 851 iocp->ioc_rval = 0; 852 iocp->ioc_cmd = tp->t_ioccmd; 853 putnext(q, mp); 854 return; 855 } 856 857 case TIOCGETC: 858 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 859 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 860 /* recycle the reply's buffer */ 861 bcopy(&tp->t_curstate.t_intrc, datap->b_wptr, 862 sizeof (struct tchars)); 863 datap->b_wptr += sizeof (struct tchars); 864 break; 865 866 case TIOCGLTC: 867 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 868 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 869 /* recycle the reply's buffer */ 870 bcopy(&tp->t_curstate.t_suspc, datap->b_wptr, 871 sizeof (struct ltchars)); 872 datap->b_wptr += sizeof (struct ltchars); 873 break; 874 875 case TIOCLGET: 876 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 877 datap->b_rptr = datap->b_wptr = datap->b_datap->db_base; 878 /* recycle the reply's buffer */ 879 *(int *)datap->b_wptr = 880 ((unsigned)tp->t_curstate.t_flags) >> 16; 881 datap->b_wptr += sizeof (int); 882 break; 883 884 case TIOCSETP: 885 case TIOCSETN: 886 /* 887 * Get the current state from the GETS data, and 888 * update it. 889 */ 890 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 891 tp->t_curstate.t_erase = tp->t_new_sgttyb.sg_erase; 892 tp->t_curstate.t_kill = tp->t_new_sgttyb.sg_kill; 893 /* 894 * For new-style handling, we ignore requests to set 895 * B38400 when the current speed is over B38400. This 896 * means that we change the speed as requested if: 897 * old style (sgttyb_handling == 0) is requested 898 * the requested new speed isn't B38400 899 * the current speed is at or below B38400 900 * Note that when old style is requested, both speeds 901 * in t_curstate are set to <= B38400 by to_compat, so 902 * the first test isn't needed here. 903 * Also note that we silently allow the user to set 904 * speeds above B38400 through this interface, 905 * regardless of the style setting. This allows 906 * greater compatibility with current BSD releases. 907 */ 908 if (tp->t_new_sgttyb.sg_ispeed != B38400 || 909 tp->t_curstate.t_ispeed <= B38400) 910 tp->t_curstate.t_ispeed = tp->t_new_sgttyb.sg_ispeed; 911 if (tp->t_new_sgttyb.sg_ospeed != B38400 || 912 tp->t_curstate.t_ospeed <= B38400) 913 tp->t_curstate.t_ospeed = tp->t_new_sgttyb.sg_ospeed; 914 tp->t_curstate.t_flags = 915 (tp->t_curstate.t_flags & 0xffff0000) | 916 (tp->t_new_sgttyb.sg_flags & 0xffff); 917 918 /* 919 * Replace the data that came up with the updated data. 920 */ 921 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 922 923 /* 924 * Send it back down as a TCSETS or TCSETSF. 925 */ 926 iocp->ioc_cmd = (tp->t_ioccmd == TIOCSETP) ? TCSETSF : TCSETS; 927 goto senddown; 928 929 case TIOCSETC: 930 /* 931 * Get the current state from the GETS data, and 932 * update it. 933 */ 934 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 935 bcopy(&tp->t_new_tchars, 936 &tp->t_curstate.t_intrc, sizeof (struct tchars)); 937 938 /* 939 * Replace the data that came up with the updated data. 940 */ 941 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 942 943 /* 944 * Send it back down as a TCSETS. 945 */ 946 iocp->ioc_cmd = TCSETS; 947 goto senddown; 948 949 case TIOCSLTC: 950 /* 951 * Get the current state from the GETS data, and 952 * update it. 953 */ 954 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 955 bcopy(&tp->t_new_ltchars, 956 &tp->t_curstate.t_suspc, sizeof (struct ltchars)); 957 958 /* 959 * Replace the data that came up with the updated data. 960 */ 961 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 962 963 /* 964 * Send it back down as a TCSETS. 965 */ 966 iocp->ioc_cmd = TCSETS; 967 goto senddown; 968 969 case TIOCLBIS: 970 /* 971 * Get the current state from the GETS data, and 972 * update it. 973 */ 974 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 975 tp->t_curstate.t_flags |= (tp->t_new_lflags << 16); 976 977 /* 978 * Replace the data that came up with the updated data. 979 */ 980 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 981 982 /* 983 * Send it back down as a TCSETS. 984 */ 985 iocp->ioc_cmd = TCSETS; 986 goto senddown; 987 988 case TIOCLBIC: 989 /* 990 * Get the current state from the GETS data, and 991 * update it. 992 */ 993 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 994 tp->t_curstate.t_flags &= ~(tp->t_new_lflags << 16); 995 996 /* 997 * Replace the data that came up with the updated data. 998 */ 999 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 1000 1001 /* 1002 * Send it back down as a TCSETS. 1003 */ 1004 iocp->ioc_cmd = TCSETS; 1005 goto senddown; 1006 1007 case TIOCLSET: 1008 /* 1009 * Get the current state from the GETS data, and 1010 * update it. 1011 */ 1012 to_compat((struct termios *)datap->b_rptr, &tp->t_curstate); 1013 tp->t_curstate.t_flags &= 0xffff; 1014 tp->t_curstate.t_flags |= (tp->t_new_lflags << 16); 1015 1016 /* 1017 * Replace the data that came up with the updated data. 1018 */ 1019 from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr); 1020 1021 /* 1022 * Send it back down as a TCSETS. 1023 */ 1024 iocp->ioc_cmd = TCSETS; 1025 goto senddown; 1026 1027 case TIOCHPCL: 1028 /* 1029 * Replace the data that came up with the updated data. 1030 */ 1031 ((struct termios *)datap->b_rptr)->c_cflag |= HUPCL; 1032 1033 /* 1034 * Send it back down as a TCSETS. 1035 */ 1036 iocp->ioc_cmd = TCSETS; 1037 goto senddown; 1038 1039 case TCSETSF: 1040 /* 1041 * We're acknowledging the terminal reset ioctl that we sent 1042 * when the module was opened. 1043 */ 1044 tp->t_state &= ~(TS_IOCWAIT | TS_TIOCNAK); 1045 freemsg(mp); 1046 return; 1047 1048 default: 1049 cmn_err(CE_WARN, "ttcompat: Unexpected ioctl acknowledgment\n"); 1050 } 1051 1052 /* 1053 * All the calls that return something return 0. 1054 */ 1055 tp->t_state &= ~TS_IOCWAIT; /* we got what we wanted */ 1056 iocp->ioc_rval = 0; 1057 1058 /* copy out the data - ioctl transparency */ 1059 iocp->ioc_cmd = tp->t_ioccmd; 1060 ttcopyout(q, mp); 1061 return; 1062 1063 senddown: 1064 /* 1065 * Send a "get state" reply back down, with suitably-modified 1066 * state, as a "set state" "ioctl". 1067 */ 1068 tp->t_state &= ~TS_IOCWAIT; 1069 mp->b_datap->db_type = M_IOCTL; 1070 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 1071 putnext(WR(q), mp); 1072 } 1073 /* Called from ttcompatrput M_IOCACK processing. */ 1074 /* Copies out the data using M_COPYOUT messages */ 1075 1076 static void 1077 ttcopyout(queue_t *q, mblk_t *mp) 1078 { 1079 struct copyreq *cqp; 1080 ttcompat_state_t *tp; 1081 1082 tp = (ttcompat_state_t *)q->q_ptr; 1083 1084 mp->b_datap->db_type = M_COPYOUT; 1085 cqp = (struct copyreq *)mp->b_rptr; 1086 cqp->cq_addr = (caddr_t)tp->t_arg; /* retrieve the 3rd argument */ 1087 tp->t_arg = 0; /* clear it since we don't need it anymore */ 1088 switch (tp->t_ioccmd) { 1089 case TIOCGLTC: 1090 cqp->cq_size = sizeof (struct ltchars); 1091 break; 1092 case TIOCGETC: 1093 cqp->cq_size = sizeof (struct tchars); 1094 break; 1095 case TIOCLGET: 1096 cqp->cq_size = sizeof (int); 1097 break; 1098 default: 1099 cmn_err(CE_WARN, 1100 "ttcompat: Unknown ioctl to copyout\n"); 1101 break; 1102 } 1103 cqp->cq_flag = 0; 1104 cqp->cq_private = NULL; 1105 tp->t_state |= TS_W_OUT; 1106 putnext(q, mp); 1107 } 1108 1109 1110 /* 1111 * Called when an M_IOCNAK message is seen on the read queue; if this is 1112 * the response we were waiting for, cancel the wait. Pass the reply up; 1113 * if we were waiting for this response, we can't complete the "ioctl" and 1114 * the NAK will tell that to the guy above us. 1115 * If this wasn't the response we were waiting for, just pass it up. 1116 */ 1117 static void 1118 ttcompat_ioctl_nak(queue_t *q, mblk_t *mp) 1119 { 1120 ttcompat_state_t *tp; 1121 struct iocblk *iocp; 1122 1123 iocp = (struct iocblk *)mp->b_rptr; 1124 tp = (ttcompat_state_t *)q->q_ptr; 1125 1126 if (tp->t_state&TS_IOCWAIT && iocp->ioc_id == tp->t_iocid) { 1127 tp->t_state &= ~TS_IOCWAIT; /* this call isn't going through */ 1128 tp->t_arg = 0; /* we may have stashed the 3rd argument */ 1129 } 1130 putnext(q, mp); 1131 } 1132 1133 #define FROM_COMPAT_CHAR(to, from) { if ((to = from) == 0377) to = 0; } 1134 1135 static void 1136 from_compat(compat_state_t *csp, struct termios *termiosp) 1137 { 1138 termiosp->c_iflag = 0; 1139 termiosp->c_oflag &= (ONLRET|ONOCR); 1140 1141 termiosp->c_cflag = (termiosp->c_cflag & 1142 (CRTSCTS|CRTSXOFF|PAREXT|LOBLK|HUPCL)) | CREAD; 1143 1144 if (csp->t_ospeed > CBAUD) { 1145 termiosp->c_cflag |= ((csp->t_ospeed - CBAUD - 1) & CBAUD) | 1146 CBAUDEXT; 1147 } else { 1148 termiosp->c_cflag |= csp->t_ospeed & CBAUD; 1149 } 1150 1151 if (csp->t_ospeed != csp->t_ispeed) { 1152 if (csp->t_ispeed > (CIBAUD >> IBSHIFT)) { 1153 termiosp->c_cflag |= CIBAUDEXT | 1154 (((csp->t_ispeed - (CIBAUD >> IBSHIFT) - 1) << 1155 IBSHIFT) & CIBAUD); 1156 } else { 1157 termiosp->c_cflag |= (csp->t_ispeed << IBSHIFT) & 1158 CIBAUD; 1159 } 1160 /* hang up if ispeed=0 */ 1161 if (csp->t_ispeed == 0) 1162 termiosp->c_cflag &= ~CBAUD & ~CBAUDEXT; 1163 } 1164 if (csp->t_ispeed == B110 || csp->t_xflags & STOPB) 1165 termiosp->c_cflag |= CSTOPB; 1166 termiosp->c_lflag = ECHOK; 1167 FROM_COMPAT_CHAR(termiosp->c_cc[VERASE], csp->t_erase); 1168 FROM_COMPAT_CHAR(termiosp->c_cc[VKILL], csp->t_kill); 1169 FROM_COMPAT_CHAR(termiosp->c_cc[VINTR], csp->t_intrc); 1170 FROM_COMPAT_CHAR(termiosp->c_cc[VQUIT], csp->t_quitc); 1171 FROM_COMPAT_CHAR(termiosp->c_cc[VSTART], csp->t_startc); 1172 FROM_COMPAT_CHAR(termiosp->c_cc[VSTOP], csp->t_stopc); 1173 termiosp->c_cc[VEOL2] = 0; 1174 FROM_COMPAT_CHAR(termiosp->c_cc[VSUSP], csp->t_suspc); 1175 /* is this useful? */ 1176 FROM_COMPAT_CHAR(termiosp->c_cc[VDSUSP], csp->t_dsuspc); 1177 FROM_COMPAT_CHAR(termiosp->c_cc[VREPRINT], csp->t_rprntc); 1178 FROM_COMPAT_CHAR(termiosp->c_cc[VDISCARD], csp->t_flushc); 1179 FROM_COMPAT_CHAR(termiosp->c_cc[VWERASE], csp->t_werasc); 1180 FROM_COMPAT_CHAR(termiosp->c_cc[VLNEXT], csp->t_lnextc); 1181 termiosp->c_cc[VSTATUS] = 0; 1182 if (csp->t_flags & O_TANDEM) 1183 termiosp->c_iflag |= IXOFF; 1184 if (csp->t_flags & O_LCASE) { 1185 termiosp->c_iflag |= IUCLC; 1186 termiosp->c_oflag |= OLCUC; 1187 termiosp->c_lflag |= XCASE; 1188 } 1189 if (csp->t_flags & O_ECHO) 1190 termiosp->c_lflag |= ECHO; 1191 if (csp->t_flags & O_CRMOD) { 1192 termiosp->c_iflag |= ICRNL; 1193 termiosp->c_oflag |= ONLCR; 1194 switch (csp->t_flags & O_CRDELAY) { 1195 1196 case O_CR1: 1197 termiosp->c_oflag |= CR2; 1198 break; 1199 1200 case O_CR2: 1201 termiosp->c_oflag |= CR3; 1202 break; 1203 } 1204 } else { 1205 if ((csp->t_flags & O_NLDELAY) == O_NL1) 1206 termiosp->c_oflag |= ONLRET|CR1; /* tty37 */ 1207 } 1208 if ((csp->t_flags & O_NLDELAY) == O_NL2) 1209 termiosp->c_oflag |= NL1; 1210 /* 1211 * When going into RAW mode, the special characters controlled by the 1212 * POSIX IEXTEN bit no longer apply; when leaving, they do. 1213 */ 1214 if (csp->t_flags & O_RAW) { 1215 termiosp->c_cflag |= CS8; 1216 termiosp->c_iflag &= ~(ICRNL|IUCLC); 1217 termiosp->c_lflag &= ~(XCASE|IEXTEN); 1218 } else { 1219 termiosp->c_iflag |= IMAXBEL|BRKINT|IGNPAR; 1220 if (termiosp->c_cc[VSTOP] != 0 && termiosp->c_cc[VSTART] != 0) 1221 termiosp->c_iflag |= IXON; 1222 if (csp->t_flags & O_LITOUT) 1223 termiosp->c_cflag |= CS8; 1224 else { 1225 if (csp->t_flags & O_PASS8) 1226 termiosp->c_cflag |= CS8; 1227 /* XXX - what about 8 bits plus parity? */ 1228 else { 1229 switch (csp->t_flags & (O_EVENP|O_ODDP)) { 1230 1231 case 0: 1232 termiosp->c_iflag |= ISTRIP; 1233 termiosp->c_cflag |= CS8; 1234 break; 1235 1236 case O_EVENP: 1237 termiosp->c_iflag |= INPCK|ISTRIP; 1238 termiosp->c_cflag |= CS7|PARENB; 1239 break; 1240 1241 case O_ODDP: 1242 termiosp->c_iflag |= INPCK|ISTRIP; 1243 termiosp->c_cflag |= CS7|PARENB|PARODD; 1244 break; 1245 1246 case O_EVENP|O_ODDP: 1247 termiosp->c_iflag |= ISTRIP; 1248 termiosp->c_cflag |= CS7|PARENB; 1249 break; 1250 } 1251 } 1252 if (!(csp->t_xflags & NOPOST)) 1253 termiosp->c_oflag |= OPOST; 1254 } 1255 termiosp->c_lflag |= IEXTEN; 1256 if (!(csp->t_xflags & NOISIG)) 1257 termiosp->c_lflag |= ISIG; 1258 if (!(csp->t_flags & O_CBREAK)) 1259 termiosp->c_lflag |= ICANON; 1260 if (csp->t_flags & O_CTLECH) 1261 termiosp->c_lflag |= ECHOCTL; 1262 } 1263 switch (csp->t_flags & O_TBDELAY) { 1264 1265 case O_TAB1: 1266 termiosp->c_oflag |= TAB1; 1267 break; 1268 1269 case O_TAB2: 1270 termiosp->c_oflag |= TAB2; 1271 break; 1272 1273 case O_XTABS: 1274 termiosp->c_oflag |= TAB3; 1275 break; 1276 } 1277 if (csp->t_flags & O_VTDELAY) 1278 termiosp->c_oflag |= FFDLY; 1279 if (csp->t_flags & O_BSDELAY) 1280 termiosp->c_oflag |= BSDLY; 1281 if (csp->t_flags & O_PRTERA) 1282 termiosp->c_lflag |= ECHOPRT; 1283 if (csp->t_flags & O_CRTERA) 1284 termiosp->c_lflag |= ECHOE; 1285 if (csp->t_flags & O_TOSTOP) 1286 termiosp->c_lflag |= TOSTOP; 1287 if (csp->t_flags & O_FLUSHO) 1288 termiosp->c_lflag |= FLUSHO; 1289 if (csp->t_flags & O_NOHANG) 1290 termiosp->c_cflag |= CLOCAL; 1291 if (csp->t_flags & O_CRTKIL) 1292 termiosp->c_lflag |= ECHOKE; 1293 if (csp->t_flags & O_PENDIN) 1294 termiosp->c_lflag |= PENDIN; 1295 if (!(csp->t_flags & O_DECCTQ)) 1296 termiosp->c_iflag |= IXANY; 1297 if (csp->t_flags & O_NOFLSH) 1298 termiosp->c_lflag |= NOFLSH; 1299 if (termiosp->c_lflag & ICANON) { 1300 FROM_COMPAT_CHAR(termiosp->c_cc[VEOF], csp->t_eofc); 1301 FROM_COMPAT_CHAR(termiosp->c_cc[VEOL], csp->t_brkc); 1302 } else { 1303 termiosp->c_cc[VMIN] = 1; 1304 termiosp->c_cc[VTIME] = 0; 1305 } 1306 } 1307 1308 #define TO_COMPAT_CHAR(to, from) { if ((to = from) == 0) to = (uchar_t)0377; } 1309 1310 static void 1311 to_compat(struct termios *termiosp, compat_state_t *csp) 1312 { 1313 csp->t_xflags &= (NOISIG|NOPOST); 1314 csp->t_ospeed = termiosp->c_cflag & CBAUD; 1315 csp->t_ispeed = (termiosp->c_cflag & CIBAUD) >> IBSHIFT; 1316 if (sgttyb_handling > 0) { 1317 if (termiosp->c_cflag & CBAUDEXT) 1318 csp->t_ospeed += CBAUD + 1; 1319 if (termiosp->c_cflag & CIBAUDEXT) 1320 csp->t_ispeed += (CIBAUD >> IBSHIFT) + 1; 1321 } 1322 if (csp->t_ispeed == 0) 1323 csp->t_ispeed = csp->t_ospeed; 1324 if ((termiosp->c_cflag & CSTOPB) && csp->t_ispeed != B110) 1325 csp->t_xflags |= STOPB; 1326 TO_COMPAT_CHAR(csp->t_erase, termiosp->c_cc[VERASE]); 1327 TO_COMPAT_CHAR(csp->t_kill, termiosp->c_cc[VKILL]); 1328 TO_COMPAT_CHAR(csp->t_intrc, termiosp->c_cc[VINTR]); 1329 TO_COMPAT_CHAR(csp->t_quitc, termiosp->c_cc[VQUIT]); 1330 TO_COMPAT_CHAR(csp->t_startc, termiosp->c_cc[VSTART]); 1331 TO_COMPAT_CHAR(csp->t_stopc, termiosp->c_cc[VSTOP]); 1332 TO_COMPAT_CHAR(csp->t_suspc, termiosp->c_cc[VSUSP]); 1333 TO_COMPAT_CHAR(csp->t_dsuspc, termiosp->c_cc[VDSUSP]); 1334 TO_COMPAT_CHAR(csp->t_rprntc, termiosp->c_cc[VREPRINT]); 1335 TO_COMPAT_CHAR(csp->t_flushc, termiosp->c_cc[VDISCARD]); 1336 TO_COMPAT_CHAR(csp->t_werasc, termiosp->c_cc[VWERASE]); 1337 TO_COMPAT_CHAR(csp->t_lnextc, termiosp->c_cc[VLNEXT]); 1338 csp->t_flags &= (O_CTLECH|O_LITOUT|O_PASS8|O_ODDP|O_EVENP); 1339 if (termiosp->c_iflag & IXOFF) 1340 csp->t_flags |= O_TANDEM; 1341 if (!(termiosp->c_iflag & 1342 (IMAXBEL|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP| 1343 INLCR|IGNCR|ICRNL|IUCLC|IXON)) && 1344 !(termiosp->c_oflag & OPOST) && 1345 (termiosp->c_cflag & (CSIZE|PARENB)) == CS8 && 1346 !(termiosp->c_lflag & (ISIG|ICANON|XCASE|IEXTEN))) 1347 csp->t_flags |= O_RAW; 1348 else { 1349 if (!(termiosp->c_iflag & IXON)) { 1350 csp->t_startc = (uchar_t)0377; 1351 csp->t_stopc = (uchar_t)0377; 1352 } 1353 if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8 && 1354 !(termiosp->c_oflag & OPOST)) 1355 csp->t_flags |= O_LITOUT; 1356 else { 1357 csp->t_flags &= ~O_LITOUT; 1358 if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8) { 1359 if (!(termiosp->c_iflag & ISTRIP)) 1360 csp->t_flags |= O_PASS8; 1361 } else { 1362 csp->t_flags &= ~(O_ODDP|O_EVENP|O_PASS8); 1363 if (termiosp->c_cflag & PARODD) 1364 csp->t_flags |= O_ODDP; 1365 else if (termiosp->c_iflag & INPCK) 1366 csp->t_flags |= O_EVENP; 1367 else 1368 csp->t_flags |= O_ODDP|O_EVENP; 1369 } 1370 if (!(termiosp->c_oflag & OPOST)) 1371 csp->t_xflags |= NOPOST; 1372 else 1373 csp->t_xflags &= ~NOPOST; 1374 } 1375 if (!(termiosp->c_lflag & ISIG)) 1376 csp->t_xflags |= NOISIG; 1377 else 1378 csp->t_xflags &= ~NOISIG; 1379 if (!(termiosp->c_lflag & ICANON)) 1380 csp->t_flags |= O_CBREAK; 1381 if (termiosp->c_lflag & ECHOCTL) 1382 csp->t_flags |= O_CTLECH; 1383 else 1384 csp->t_flags &= ~O_CTLECH; 1385 } 1386 if (termiosp->c_oflag & OLCUC) 1387 csp->t_flags |= O_LCASE; 1388 if (termiosp->c_lflag&ECHO) 1389 csp->t_flags |= O_ECHO; 1390 if (termiosp->c_oflag & ONLCR) { 1391 csp->t_flags |= O_CRMOD; 1392 switch (termiosp->c_oflag & CRDLY) { 1393 1394 case CR2: 1395 csp->t_flags |= O_CR1; 1396 break; 1397 1398 case CR3: 1399 csp->t_flags |= O_CR2; 1400 break; 1401 } 1402 } else { 1403 if ((termiosp->c_oflag & CR1) && 1404 (termiosp->c_oflag & ONLRET)) 1405 csp->t_flags |= O_NL1; /* tty37 */ 1406 } 1407 if ((termiosp->c_oflag & ONLRET) && (termiosp->c_oflag & NL1)) 1408 csp->t_flags |= O_NL2; 1409 switch (termiosp->c_oflag & TABDLY) { 1410 1411 case TAB1: 1412 csp->t_flags |= O_TAB1; 1413 break; 1414 1415 case TAB2: 1416 csp->t_flags |= O_TAB2; 1417 break; 1418 1419 case XTABS: 1420 csp->t_flags |= O_XTABS; 1421 break; 1422 } 1423 if (termiosp->c_oflag & FFDLY) 1424 csp->t_flags |= O_VTDELAY; 1425 if (termiosp->c_oflag & BSDLY) 1426 csp->t_flags |= O_BSDELAY; 1427 if (termiosp->c_lflag & ECHOPRT) 1428 csp->t_flags |= O_PRTERA; 1429 if (termiosp->c_lflag & ECHOE) 1430 csp->t_flags |= (O_CRTERA|O_CRTBS); 1431 if (termiosp->c_lflag & TOSTOP) 1432 csp->t_flags |= O_TOSTOP; 1433 if (termiosp->c_lflag & FLUSHO) 1434 csp->t_flags |= O_FLUSHO; 1435 if (termiosp->c_cflag & CLOCAL) 1436 csp->t_flags |= O_NOHANG; 1437 if (termiosp->c_lflag & ECHOKE) 1438 csp->t_flags |= O_CRTKIL; 1439 if (termiosp->c_lflag & PENDIN) 1440 csp->t_flags |= O_PENDIN; 1441 if (!(termiosp->c_iflag & IXANY)) 1442 csp->t_flags |= O_DECCTQ; 1443 if (termiosp->c_lflag & NOFLSH) 1444 csp->t_flags |= O_NOFLSH; 1445 if (termiosp->c_lflag & ICANON) { 1446 TO_COMPAT_CHAR(csp->t_eofc, termiosp->c_cc[VEOF]); 1447 TO_COMPAT_CHAR(csp->t_brkc, termiosp->c_cc[VEOL]); 1448 } else { 1449 termiosp->c_cc[VMIN] = 1; 1450 termiosp->c_cc[VTIME] = 0; 1451 } 1452 } 1453