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