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