1/* 2 * Copyright (c) 1997-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1982, 1986, 1989, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Berkeley and its contributors. 44 * 4. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95 61 */ 62 63/* 64 * Pseudo-teletype Driver 65 * (Actually two drivers, requiring two entries in 'cdevsw') 66 */ 67#include "pty.h" /* XXX */ 68 69#include <sys/param.h> 70#include <sys/systm.h> 71#include <sys/ioctl.h> 72#include <sys/proc_internal.h> 73#include <sys/kauth.h> 74#include <sys/tty.h> 75#include <sys/conf.h> 76#include <sys/file_internal.h> 77#include <sys/uio_internal.h> 78#include <sys/kernel.h> 79#include <sys/vnode.h> 80#include <sys/user.h> 81#include <sys/signalvar.h> 82 83#define d_devtotty_t struct tty ** 84 85#ifdef d_stop_t 86#undef d_stop_t 87#endif 88typedef void d_stop_t(struct tty *tp, int rw); 89 90/* XXX function should be removed??? */ 91int pty_init(int n_ptys); 92 93/* XXX should be a devfs function */ 94int _devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid); 95 96static void ptsstart(struct tty *tp); 97static void ptcwakeup(struct tty *tp, int flag); 98 99__XNU_PRIVATE_EXTERN d_open_t ptsopen; 100__XNU_PRIVATE_EXTERN d_close_t ptsclose; 101__XNU_PRIVATE_EXTERN d_read_t ptsread; 102__XNU_PRIVATE_EXTERN d_write_t ptswrite; 103__XNU_PRIVATE_EXTERN d_ioctl_t ptyioctl; 104__XNU_PRIVATE_EXTERN d_stop_t ptsstop; 105__XNU_PRIVATE_EXTERN d_devtotty_t ptydevtotty; 106__XNU_PRIVATE_EXTERN d_open_t ptcopen; 107__XNU_PRIVATE_EXTERN d_close_t ptcclose; 108__XNU_PRIVATE_EXTERN d_read_t ptcread; 109__XNU_PRIVATE_EXTERN d_write_t ptcwrite; 110__XNU_PRIVATE_EXTERN d_select_t ptcselect; 111 112#if NPTY == 1 113#undef NPTY 114#define NPTY 32 /* crude XXX */ 115#warning You have only one pty defined, redefining to 32. 116#endif 117 118#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 119 120/* 121 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 122 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 123 */ 124/* All references to have been changed to indirections in the file */ 125__private_extern__ struct tty *pt_tty[NPTY] = { NULL }; 126 127static struct pt_ioctl { 128 int pt_flags; 129 struct selinfo pt_selr, pt_selw; 130 u_char pt_send; 131 u_char pt_ucntl; 132 void *pt_devhandle; /* slave device handle for grantpt() */ 133} pt_ioctl[NPTY]; /* XXX */ 134static int npty = NPTY; /* for pstat -t */ 135 136#define PF_PKT 0x08 /* packet mode */ 137#define PF_STOPPED 0x10 /* user told stopped */ 138#define PF_REMOTE 0x20 /* remote and flow controlled input */ 139#define PF_NOSTOP 0x40 140#define PF_UCNTL 0x80 /* user control mode */ 141 142#ifndef DEVFS 143int 144pty_init(__unused int n_ptys) 145{ 146 return 0; 147} 148#else 149#include <miscfs/devfs/devfs.h> 150#define START_CHAR 'p' 151#define HEX_BASE 16 152int 153pty_init(int n_ptys) 154{ 155 int i; 156 int j; 157 158 /* create the pseudo tty device nodes */ 159 for (j = 0; j < 10; j++) { 160 for (i = 0; i < HEX_BASE; i++) { 161 int m = j * HEX_BASE + i; 162 if (m == n_ptys) 163 goto done; 164 pt_ioctl[m].pt_devhandle = devfs_make_node(makedev(4, m), 165 DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, 166 "tty%c%x", j + START_CHAR, i); 167 (void)devfs_make_node(makedev(5, m), 168 DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, 169 "pty%c%x", j + START_CHAR, i); 170 } 171 } 172 done: 173 return (0); 174} 175#endif /* DEVFS */ 176 177__private_extern__ int 178ptsopen(dev_t dev, int flag, __unused int devtype, __unused struct proc *p) 179{ 180 struct tty *tp; 181 int error; 182 183 /* 184 * You will see this sort of code coming up in diffs later both 185 * the ttymalloc and the tp indirection. 186 */ 187 if (minor(dev) >= npty) { 188 error = ENXIO; 189 goto err; 190 } 191 if (!pt_tty[minor(dev)]) { 192 /* 193 * If we can't allocate a new one, act as if we had run out 194 * of device nodes. 195 */ 196 if ((tp = pt_tty[minor(dev)] = ttymalloc()) == NULL) { 197 error = ENXIO; 198 goto err; 199 } 200 } else 201 tp = pt_tty[minor(dev)]; 202 203 tty_lock(tp); 204 205 if ((tp->t_state & TS_ISOPEN) == 0) { 206 termioschars(&tp->t_termios); /* Set up default chars */ 207 tp->t_iflag = TTYDEF_IFLAG; 208 tp->t_oflag = TTYDEF_OFLAG; 209 tp->t_lflag = TTYDEF_LFLAG; 210 tp->t_cflag = TTYDEF_CFLAG; 211 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 212 ttsetwater(tp); /* would be done in xxparam() */ 213 } else if (tp->t_state&TS_XCLUDE && suser(kauth_cred_get(), NULL)) { 214 error = EBUSY; 215 goto out; 216 } 217 if (tp->t_oproc) /* Ctrlr still around. */ 218 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 219 while ((tp->t_state & TS_CARR_ON) == 0) { 220 if (flag&FNONBLOCK) 221 break; 222 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 223 "ptsopn", 0); 224 if (error) 225 goto out; 226 } 227 error = (*linesw[tp->t_line].l_open)(dev, tp); 228 if (error == 0) 229 ptcwakeup(tp, FREAD|FWRITE); 230 231out: 232 tty_unlock(tp); 233err: 234 return (error); 235} 236 237__private_extern__ int 238ptsclose(dev_t dev, int flag, __unused int mode, __unused proc_t p) 239{ 240 struct tty *tp; 241 int err; 242 243 /* 244 * This is temporary until the VSX conformance tests 245 * are fixed. They are hanging with a deadlock 246 * where close(pts) will not complete without t_timeout set 247 */ 248#define FIX_VSX_HANG 1 249#ifdef FIX_VSX_HANG 250 int save_timeout; 251#endif 252 253 tp = pt_tty[minor(dev)]; 254 tty_lock(tp); 255#ifdef FIX_VSX_HANG 256 save_timeout = tp->t_timeout; 257 tp->t_timeout = 60; 258#endif 259 err = (*linesw[tp->t_line].l_close)(tp, flag); 260 ptsstop(tp, FREAD|FWRITE); 261 (void) ttyclose(tp); 262#ifdef FIX_VSX_HANG 263 tp->t_timeout = save_timeout; 264#endif 265 tty_unlock(tp); 266 return (err); 267} 268 269__private_extern__ int 270ptsread(dev_t dev, struct uio *uio, int flag) 271{ 272 struct proc *p = current_proc(); 273 struct tty *tp = pt_tty[minor(dev)]; 274 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 275 int error = 0; 276 struct uthread *ut; 277 struct pgrp *pg; 278 279 tty_lock(tp); 280 281 ut = (struct uthread *)get_bsdthread_info(current_thread()); 282again: 283 if (pti->pt_flags & PF_REMOTE) { 284 while (isbackground(p, tp)) { 285 if ((p->p_sigignore & sigmask(SIGTTIN)) || 286 (ut->uu_sigmask & sigmask(SIGTTIN)) || 287 p->p_lflag & P_LPPWAIT) { 288 error = EIO; 289 goto out; 290 } 291 292 293 pg = proc_pgrp(p); 294 if (pg == PGRP_NULL) { 295 error = EIO; 296 goto out; 297 } 298 /* 299 * SAFE: We about to drop the lock ourselves by 300 * SAFE: erroring out or sleeping anyway. 301 */ 302 tty_unlock(tp); 303 if (pg->pg_jobc == 0) { 304 pg_rele(pg); 305 tty_lock(tp); 306 error = EIO; 307 goto out; 308 } 309 pgsignal(pg, SIGTTIN, 1); 310 pg_rele(pg); 311 tty_lock(tp); 312 313 error = ttysleep(tp, &ptsread, TTIPRI | PCATCH | PTTYBLOCK, "ptsbg", 314 hz); 315 if (error) 316 goto out; 317 } 318 if (tp->t_canq.c_cc == 0) { 319 if (flag & IO_NDELAY) { 320 error = EWOULDBLOCK; 321 goto out; 322 } 323 error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH, 324 "ptsin", 0); 325 if (error) 326 goto out; 327 goto again; 328 } 329 while (tp->t_canq.c_cc > 1 && uio_resid(uio) > 0) { 330 int cc; 331 char buf[BUFSIZ]; 332 333 cc = min(uio_resid(uio), BUFSIZ); 334 // Don't copy the very last byte 335 cc = min(cc, tp->t_canq.c_cc - 1); 336 cc = q_to_b(&tp->t_canq, (u_char *)buf, cc); 337 error = uiomove(buf, cc, uio); 338 if (error) 339 break; 340 } 341 if (tp->t_canq.c_cc == 1) 342 (void) getc(&tp->t_canq); 343 if (tp->t_canq.c_cc) 344 goto out; 345 } else 346 if (tp->t_oproc) 347 error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 348 ptcwakeup(tp, FWRITE); 349out: 350 tty_unlock(tp); 351 return (error); 352} 353 354/* 355 * Write to pseudo-tty. 356 * Wakeups of controlling tty will happen 357 * indirectly, when tty driver calls ptsstart. 358 */ 359__private_extern__ int 360ptswrite(dev_t dev, struct uio *uio, int flag) 361{ 362 struct tty *tp; 363 int error; 364 365 tp = pt_tty[minor(dev)]; 366 367 tty_lock(tp); 368 369 if (tp->t_oproc == 0) 370 error = EIO; 371 else 372 error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 373 374 tty_unlock(tp); 375 376 return (error); 377} 378 379/* 380 * Start output on pseudo-tty. 381 * Wake up process selecting or sleeping for input from controlling tty. 382 * 383 * t_oproc for this driver; called from within the line discipline 384 * 385 * Locks: Assumes tp is locked on entry, remains locked on exit 386 */ 387static void 388ptsstart(struct tty *tp) 389{ 390 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 391 392 if (tp->t_state & TS_TTSTOP) 393 goto out; 394 if (pti->pt_flags & PF_STOPPED) { 395 pti->pt_flags &= ~PF_STOPPED; 396 pti->pt_send = TIOCPKT_START; 397 } 398 ptcwakeup(tp, FREAD); 399out: 400 return; 401} 402 403/* 404 * Locks: Assumes tty_lock() is held over this call. 405 */ 406static void 407ptcwakeup(struct tty *tp, int flag) 408{ 409 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 410 411 if (flag & FREAD) { 412 selwakeup(&pti->pt_selr); 413 wakeup(TSA_PTC_READ(tp)); 414 } 415 if (flag & FWRITE) { 416 selwakeup(&pti->pt_selw); 417 wakeup(TSA_PTC_WRITE(tp)); 418 } 419} 420 421__private_extern__ int 422ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p) 423{ 424 struct tty *tp; 425 struct pt_ioctl *pti; 426 int error = 0; 427 428 if (minor(dev) >= npty) { 429 error = ENXIO; 430 goto out; 431 } 432 if(!pt_tty[minor(dev)]) { 433 tp = pt_tty[minor(dev)] = ttymalloc(); 434 } else 435 tp = pt_tty[minor(dev)]; 436 437 tty_lock(tp); 438 439 /* If master is open OR slave is still draining, pty is still busy */ 440 if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) { 441 error = EBUSY; 442 } else { 443 tp->t_oproc = ptsstart; 444 CLR(tp->t_state, TS_ZOMBIE); 445#ifdef sun4c 446 tp->t_stop = ptsstop; 447#endif 448 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 449 tp->t_lflag &= ~EXTPROC; 450 pti = &pt_ioctl[minor(dev)]; 451 pti->pt_flags = 0; 452 pti->pt_send = 0; 453 pti->pt_ucntl = 0; 454 } 455 456 tty_unlock(tp); 457 458out: 459 return (error); 460} 461 462__private_extern__ int 463ptcclose(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p) 464{ 465 struct tty *tp = pt_tty[minor(dev)]; 466 467 tty_lock(tp); 468 469 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 470 471 /* 472 * XXX MDMBUF makes no sense for ptys but would inhibit the above 473 * l_modem(). CLOCAL makes sense but isn't supported. Special 474 * l_modem()s that ignore carrier drop make no sense for ptys but 475 * may be in use because other parts of the line discipline make 476 * sense for ptys. Recover by doing everything that a normal 477 * ttymodem() would have done except for sending a SIGHUP. 478 */ 479 if (tp->t_state & TS_ISOPEN) { 480 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 481 tp->t_state |= TS_ZOMBIE; 482 ttyflush(tp, FREAD | FWRITE); 483 } 484 485 tp->t_oproc = 0; /* mark closed */ 486 487 tty_unlock(tp); 488 489 return (0); 490} 491 492__private_extern__ int 493ptcread(dev_t dev, struct uio *uio, int flag) 494{ 495 struct tty *tp = pt_tty[minor(dev)]; 496 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 497 char buf[BUFSIZ]; 498 int error = 0, cc; 499 500 tty_lock(tp); 501 502 /* 503 * We want to block until the slave 504 * is open, and there's something to read; 505 * but if we lost the slave or we're NBIO, 506 * then return the appropriate error instead. 507 */ 508 for (;;) { 509 if (tp->t_state&TS_ISOPEN) { 510 if (pti->pt_flags&PF_PKT && pti->pt_send) { 511 error = ureadc((int)pti->pt_send, uio); 512 if (error) 513 goto out; 514 if (pti->pt_send & TIOCPKT_IOCTL) { 515 cc = min(uio_resid(uio), 516 sizeof(tp->t_termios)); 517 uiomove((caddr_t)&tp->t_termios, cc, 518 uio); 519 } 520 pti->pt_send = 0; 521 goto out; 522 } 523 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 524 error = ureadc((int)pti->pt_ucntl, uio); 525 if (error) 526 goto out; 527 pti->pt_ucntl = 0; 528 goto out; 529 } 530 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 531 break; 532 } 533 if ((tp->t_state & TS_CONNECTED) == 0) 534 goto out; /* EOF */ 535 if (flag & IO_NDELAY) { 536 error = EWOULDBLOCK; 537 goto out; 538 } 539 error = ttysleep(tp, TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 540 if (error) 541 goto out; 542 } 543 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 544 error = ureadc(0, uio); 545 while (uio_resid(uio) > 0 && error == 0) { 546 cc = q_to_b(&tp->t_outq, (u_char *)buf, min(uio_resid(uio), BUFSIZ)); 547 if (cc <= 0) 548 break; 549 error = uiomove(buf, cc, uio); 550 } 551 (*linesw[tp->t_line].l_start)(tp); 552 553out: 554 tty_unlock(tp); 555 556 return (error); 557} 558 559/* 560 * Line discipline callback 561 * 562 * Locks: tty_lock() is assumed held on entry and exit. 563 */ 564__private_extern__ void 565ptsstop(struct tty *tp, int flush) 566{ 567 struct pt_ioctl *pti; 568 int flag; 569 570 pti = &pt_ioctl[minor(tp->t_dev)]; 571 572 /* note: FLUSHREAD and FLUSHWRITE already ok */ 573 if (flush == 0) { 574 flush = TIOCPKT_STOP; 575 pti->pt_flags |= PF_STOPPED; 576 } else 577 pti->pt_flags &= ~PF_STOPPED; 578 pti->pt_send |= flush; 579 /* change of perspective */ 580 flag = 0; 581 if (flush & FREAD) 582 flag |= FWRITE; 583 if (flush & FWRITE) 584 flag |= FREAD; 585 ptcwakeup(tp, flag); 586} 587 588__private_extern__ int 589ptcselect(dev_t dev, int rw, void *wql, struct proc *p) 590{ 591 struct tty *tp = pt_tty[minor(dev)]; 592 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 593 int retval = 0; 594 595 tty_lock(tp); 596 597 if ((tp->t_state & TS_CONNECTED) == 0) { 598 retval = 1; 599 goto out; 600 } 601 switch (rw) { 602 603 case FREAD: 604 /* 605 * Need to block timeouts (ttrstart). 606 */ 607 if ((tp->t_state&TS_ISOPEN) && 608 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 609 retval = 1; 610 goto out; 611 } 612 /* FALLTHROUGH */ 613 614 case 0: /* exceptional */ 615 if ((tp->t_state&TS_ISOPEN) && 616 ((pti->pt_flags&PF_PKT && pti->pt_send) || 617 (pti->pt_flags&PF_UCNTL && pti->pt_ucntl))) { 618 retval = 1; 619 goto out; 620 } 621 selrecord(p, &pti->pt_selr, wql); 622 break; 623 624 625 case FWRITE: 626 if (tp->t_state&TS_ISOPEN) { 627 if (pti->pt_flags & PF_REMOTE) { 628 if (tp->t_canq.c_cc == 0) { 629 retval = 1; 630 goto out; 631 } 632 } else { 633 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) { 634 retval = 1; 635 goto out; 636 } 637 if (tp->t_canq.c_cc == 0 && (tp->t_lflag&ICANON)) { 638 retval = 1; 639 goto out; 640 } 641 } 642 } 643 selrecord(p, &pti->pt_selw, wql); 644 break; 645 646 } 647out: 648 tty_unlock(tp); 649 650 return (retval); 651} 652 653__private_extern__ int 654ptcwrite(dev_t dev, struct uio *uio, int flag) 655{ 656 struct tty *tp = pt_tty[minor(dev)]; 657 u_char *cp = NULL; 658 int cc = 0; 659 u_char locbuf[BUFSIZ]; 660 int wcnt = 0; 661 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 662 int error = 0; 663 664 tty_lock(tp); 665 666again: 667 if ((tp->t_state&TS_ISOPEN) == 0) 668 goto block; 669 if (pti->pt_flags & PF_REMOTE) { 670 if (tp->t_canq.c_cc) 671 goto block; 672 while ((uio_resid(uio) > 0 || cc > 0) && 673 tp->t_canq.c_cc < TTYHOG - 1) { 674 if (cc == 0) { 675 cc = min(uio_resid(uio), BUFSIZ); 676 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); 677 cp = locbuf; 678 error = uiomove((caddr_t)cp, cc, uio); 679 if (error) 680 goto out; 681 /* check again for safety */ 682 if ((tp->t_state & TS_ISOPEN) == 0) { 683 /* adjust as usual */ 684 uio_setresid(uio, (uio_resid(uio) + cc)); 685 error = EIO; 686 goto out; 687 } 688 } 689 if (cc > 0) { 690 cc = b_to_q((u_char *)cp, cc, &tp->t_canq); 691 /* 692 * XXX we don't guarantee that the canq size 693 * is >= TTYHOG, so the above b_to_q() may 694 * leave some bytes uncopied. However, space 695 * is guaranteed for the null terminator if 696 * we don't fail here since (TTYHOG - 1) is 697 * not a multiple of CBSIZE. 698 */ 699 if (cc > 0) 700 break; 701 } 702 } 703 /* adjust for data copied in but not written */ 704 uio_setresid(uio, (uio_resid(uio) + cc)); 705 (void) putc(0, &tp->t_canq); 706 ttwakeup(tp); 707 wakeup(TSA_PTS_READ(tp)); 708 goto out; 709 } 710 while (uio_resid(uio) > 0 || cc > 0) { 711 if (cc == 0) { 712 cc = min(uio_resid(uio), BUFSIZ); 713 cp = locbuf; 714 error = uiomove((caddr_t)cp, cc, uio); 715 if (error) 716 goto out; 717 /* check again for safety */ 718 if ((tp->t_state & TS_ISOPEN) == 0) { 719 /* adjust for data copied in but not written */ 720 uio_setresid(uio, (uio_resid(uio) + cc)); 721 error = EIO; 722 goto out; 723 } 724 } 725 while (cc > 0) { 726 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 727 (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { 728 wakeup(TSA_HUP_OR_INPUT(tp)); 729 goto block; 730 } 731 (*linesw[tp->t_line].l_rint)(*cp++, tp); 732 wcnt++; 733 cc--; 734 } 735 cc = 0; 736 } 737out: 738 tty_unlock(tp); 739 740 return (error); 741 742block: 743 /* 744 * Come here to wait for slave to open, for space 745 * in outq, or space in rawq, or an empty canq. 746 */ 747 if ((tp->t_state & TS_CONNECTED) == 0) { 748 /* adjust for data copied in but not written */ 749 uio_setresid(uio, (uio_resid(uio) + cc)); 750 error = EIO; 751 goto out; 752 } 753 if (flag & IO_NDELAY) { 754 /* adjust for data copied in but not written */ 755 uio_setresid(uio, (uio_resid(uio) + cc)); 756 if (wcnt == 0) 757 error = EWOULDBLOCK; 758 goto out; 759 } 760 error = ttysleep(tp, TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 761 if (error) { 762 /* adjust for data copied in but not written */ 763 uio_setresid(uio, (uio_resid(uio) + cc)); 764 goto out; 765 } 766 goto again; 767} 768 769__private_extern__ int 770ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 771{ 772 struct tty *tp = pt_tty[minor(dev)]; 773 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 774 u_char *cc = tp->t_cc; 775 int stop, error = 0; 776 777 tty_lock(tp); 778 779 /* 780 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 781 * ttywflush(tp) will hang if there are characters in the outq. 782 */ 783 if (cmd == TIOCEXT) { 784 /* 785 * When the EXTPROC bit is being toggled, we need 786 * to send an TIOCPKT_IOCTL if the packet driver 787 * is turned on. 788 */ 789 if (*(int *)data) { 790 if (pti->pt_flags & PF_PKT) { 791 pti->pt_send |= TIOCPKT_IOCTL; 792 ptcwakeup(tp, FREAD); 793 } 794 tp->t_lflag |= EXTPROC; 795 } else { 796 if ((tp->t_lflag & EXTPROC) && 797 (pti->pt_flags & PF_PKT)) { 798 pti->pt_send |= TIOCPKT_IOCTL; 799 ptcwakeup(tp, FREAD); 800 } 801 tp->t_lflag &= ~EXTPROC; 802 } 803 goto out; 804 } else 805 if (cdevsw[major(dev)].d_open == ptcopen) 806 switch (cmd) { 807 808 case TIOCGPGRP: 809 /* 810 * We aviod calling ttioctl on the controller since, 811 * in that case, tp must be the controlling terminal. 812 */ 813 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 814 goto out; 815 816 case TIOCPKT: 817 if (*(int *)data) { 818 if (pti->pt_flags & PF_UCNTL) { 819 error = EINVAL; 820 goto out; 821 } 822 pti->pt_flags |= PF_PKT; 823 } else 824 pti->pt_flags &= ~PF_PKT; 825 goto out; 826 827 case TIOCUCNTL: 828 if (*(int *)data) { 829 if (pti->pt_flags & PF_PKT) { 830 error = EINVAL; 831 goto out; 832 } 833 pti->pt_flags |= PF_UCNTL; 834 } else 835 pti->pt_flags &= ~PF_UCNTL; 836 goto out; 837 838 case TIOCREMOTE: 839 if (*(int *)data) 840 pti->pt_flags |= PF_REMOTE; 841 else 842 pti->pt_flags &= ~PF_REMOTE; 843 ttyflush(tp, FREAD|FWRITE); 844 goto out; 845 846 case TIOCSETP: 847 case TIOCSETN: 848 case TIOCSETD: 849 case TIOCSETA_32: 850 case TIOCSETAW_32: 851 case TIOCSETAF_32: 852 case TIOCSETA_64: 853 case TIOCSETAW_64: 854 case TIOCSETAF_64: 855 ndflush(&tp->t_outq, tp->t_outq.c_cc); 856 break; 857 858 case TIOCSIG: 859 if (*(unsigned int *)data >= NSIG || 860 *(unsigned int *)data == 0) { 861 error = EINVAL; 862 goto out; 863 } 864 if ((tp->t_lflag&NOFLSH) == 0) 865 ttyflush(tp, FREAD|FWRITE); 866 if ((*(unsigned int *)data == SIGINFO) && 867 ((tp->t_lflag&NOKERNINFO) == 0)) 868 ttyinfo_locked(tp); 869 /* 870 * SAFE: All callers drop the lock on return and 871 * SAFE: the linesw[] will short circut this call 872 * SAFE: if the ioctl() is eaten before the lower 873 * SAFE: level code gets to see it. 874 */ 875 tty_unlock(tp); 876 tty_pgsignal(tp, *(unsigned int *)data, 1); 877 tty_lock(tp); 878 goto out; 879 880 case TIOCPTYGRANT: /* grantpt(3) */ 881 /* 882 * Change the uid of the slave to that of the calling 883 * thread, change the gid of the slave to GID_TTY, 884 * change the mode to 0620 (rw--w----). 885 */ 886 { 887 _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY); 888 goto out; 889 } 890 891 case TIOCPTYGNAME: /* ptsname(3) */ 892 /* 893 * Report the name of the slave device in *data 894 * (128 bytes max.). Use the same derivation method 895 * used for calling devfs_make_node() to create it. 896 */ 897 snprintf(data, 128, "/dev/tty%c%x", 898 START_CHAR + (minor(dev) / HEX_BASE), 899 minor(dev) % HEX_BASE); 900 error = 0; 901 goto out; 902 903 case TIOCPTYUNLK: /* unlockpt(3) */ 904 /* 905 * Unlock the slave device so that it can be opened. 906 */ 907 error = 0; 908 goto out; 909 } 910 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 911 if (error == ENOTTY) { 912 error = ttioctl_locked(tp, cmd, data, flag, p); 913 if (error == ENOTTY) { 914 if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) { 915 /* Process the UIOCMD ioctl group */ 916 if (cmd & 0xff) { 917 pti->pt_ucntl = (u_char)cmd; 918 ptcwakeup(tp, FREAD); 919 } 920 error = 0; 921 goto out; 922 } else if (cmd == TIOCSBRK || cmd == TIOCCBRK) { 923 /* 924 * POSIX conformance; rdar://3936338 925 * 926 * Clear ENOTTY in the case of setting or 927 * clearing a break failing because pty's 928 * don't support break like real serial 929 * ports. 930 */ 931 error = 0; 932 goto out; 933 } 934 } 935 } 936 937 /* 938 * If external processing and packet mode send ioctl packet. 939 */ 940 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { 941 switch(cmd) { 942 case TIOCSETA_32: 943 case TIOCSETAW_32: 944 case TIOCSETAF_32: 945 case TIOCSETA_64: 946 case TIOCSETAW_64: 947 case TIOCSETAF_64: 948 case TIOCSETP: 949 case TIOCSETN: 950 case TIOCSETC: 951 case TIOCSLTC: 952 case TIOCLBIS: 953 case TIOCLBIC: 954 case TIOCLSET: 955 pti->pt_send |= TIOCPKT_IOCTL; 956 ptcwakeup(tp, FREAD); 957 default: 958 break; 959 } 960 } 961 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 962 && CCEQ(cc[VSTART], CTRL('q')); 963 if (pti->pt_flags & PF_NOSTOP) { 964 if (stop) { 965 pti->pt_send &= ~TIOCPKT_NOSTOP; 966 pti->pt_send |= TIOCPKT_DOSTOP; 967 pti->pt_flags &= ~PF_NOSTOP; 968 ptcwakeup(tp, FREAD); 969 } 970 } else { 971 if (!stop) { 972 pti->pt_send &= ~TIOCPKT_DOSTOP; 973 pti->pt_send |= TIOCPKT_NOSTOP; 974 pti->pt_flags |= PF_NOSTOP; 975 ptcwakeup(tp, FREAD); 976 } 977 } 978out: 979 tty_unlock(tp); 980 981 return (error); 982} 983