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