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