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