tty_pty.c revision 1.55.2.2 1 /* $NetBSD: tty_pty.c,v 1.55.2.2 2001/06/21 20:07:07 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
36 */
37
38 /*
39 * Pseudo-teletype Driver
40 * (Actually two drivers, requiring two entries in 'cdevsw')
41 */
42
43 #include "opt_compat_sunos.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/ioctl.h>
48 #include <sys/lwp.h>
49 #include <sys/proc.h>
50 #include <sys/tty.h>
51 #include <sys/file.h>
52 #include <sys/uio.h>
53 #include <sys/kernel.h>
54 #include <sys/vnode.h>
55 #include <sys/signalvar.h>
56 #include <sys/uio.h>
57 #include <sys/conf.h>
58 #include <sys/poll.h>
59 #include <sys/malloc.h>
60
61 #define DEFAULT_NPTYS 16 /* default number of initial ptys */
62 #define DEFAULT_MAXPTYS 256 /* default maximum number of ptys */
63
64 /* Macros to clear/set/test flags. */
65 #define SET(t, f) (t) |= (f)
66 #define CLR(t, f) (t) &= ~((unsigned)(f))
67 #define ISSET(t, f) ((t) & (f))
68
69 #define BUFSIZ 100 /* Chunk size iomoved to/from user */
70
71 /*
72 * pts == /dev/tty[pqrs]?
73 * ptc == /dev/pty[pqrs]?
74 */
75 struct pt_softc {
76 struct tty *pt_tty;
77 int pt_flags;
78 struct selinfo pt_selr, pt_selw;
79 u_char pt_send;
80 u_char pt_ucntl;
81 };
82
83 static struct pt_softc **pt_softc = NULL; /* pty array */
84 static int npty = 0; /* for pstat -t */
85 static int maxptys = DEFAULT_MAXPTYS; /* maximum number of ptys (sysctable) */
86 static struct simplelock pt_softc_mutex = SIMPLELOCK_INITIALIZER;
87
88 #define PF_PKT 0x08 /* packet mode */
89 #define PF_STOPPED 0x10 /* user told stopped */
90 #define PF_REMOTE 0x20 /* remote and flow controlled input */
91 #define PF_NOSTOP 0x40
92 #define PF_UCNTL 0x80 /* user control mode */
93
94 void ptyattach __P((int));
95 void ptcwakeup __P((struct tty *, int));
96 int ptcopen __P((dev_t, int, int, struct proc *));
97 struct tty *ptytty __P((dev_t));
98 void ptsstart __P((struct tty *));
99 int pty_maxptys __P((int, int));
100
101 static struct pt_softc **ptyarralloc __P((int));
102 static int check_pty __P((dev_t));
103
104 /*
105 * Allocate and zero array of nelem elements.
106 */
107 static struct pt_softc **
108 ptyarralloc(nelem)
109 int nelem;
110 {
111 struct pt_softc **pt;
112 nelem += 10;
113 pt = malloc(nelem * sizeof(struct pt_softc *), M_DEVBUF, M_WAITOK);
114 memset(pt, '\0', nelem * sizeof(struct pt_softc *));
115 return pt;
116 }
117
118 /*
119 * Check if the minor is correct and ensure necessary structures
120 * are properly allocated.
121 */
122 static int
123 check_pty(dev)
124 dev_t dev;
125 {
126 struct pt_softc *pti;
127
128 if (minor(dev) >= npty) {
129 struct pt_softc **newpt;
130 int newnpty;
131
132 /* check if the requested pty can be granted */
133 if (minor(dev) >= maxptys) {
134 limit_reached:
135 tablefull("pty", "increase kern.maxptys");
136 return (ENXIO);
137 }
138
139 /*
140 * Now grab the pty array mutex - we need to ensure
141 * that the pty array is consistent while copying it's
142 * content to newly allocated, larger space; we also
143 * need to be safe against pty_maxptys().
144 */
145 simple_lock(&pt_softc_mutex);
146
147 do {
148 for(newnpty = npty; newnpty <= minor(dev);
149 newnpty *= 2);
150
151 if (newnpty > maxptys)
152 newnpty = maxptys;
153
154 simple_unlock(&pt_softc_mutex);
155 newpt = ptyarralloc(newnpty);
156 simple_lock(&pt_softc_mutex);
157
158 if (maxptys == npty) {
159 simple_unlock(&pt_softc_mutex);
160 goto limit_reached;
161 }
162 } while(newnpty > maxptys);
163
164 /*
165 * If the pty array was not enlarged while we were waiting
166 * for mutex, copy current contents of pt_softc[] to newly
167 * allocated array and start using the new bigger array.
168 */
169 if (minor(dev) >= npty) {
170 memcpy(newpt, pt_softc, npty*sizeof(struct pt_softc *));
171 free(pt_softc, M_DEVBUF);
172
173 pt_softc = newpt;
174 npty = newnpty;
175 } else {
176 /* was enlarged when waited fot lock, free new space */
177 free(newpt, M_DEVBUF);
178 }
179
180 simple_unlock(&pt_softc_mutex);
181 }
182
183 /*
184 * If the entry is not yet allocated, allocate one. The mutex is
185 * needed so that the state of pt_softc[] array is consistant
186 * in case it has been longened above.
187 */
188 if (!pt_softc[minor(dev)]) {
189 MALLOC(pti, struct pt_softc *, sizeof(struct pt_softc),
190 M_DEVBUF, M_WAITOK);
191
192 pti->pt_tty = ttymalloc();
193
194 simple_lock(&pt_softc_mutex);
195
196 /*
197 * Check the entry again - it might have been
198 * added while we were waiting for mutex.
199 */
200 if (!pt_softc[minor(dev)]) {
201 tty_attach(pti->pt_tty);
202 pt_softc[minor(dev)] = pti;
203 } else {
204 ttyfree(pti->pt_tty);
205 FREE(pti, M_DEVBUF);
206 }
207
208 simple_unlock(&pt_softc_mutex);
209 }
210
211 return (0);
212 }
213
214 /*
215 * Set maxpty in thread-safe way. Returns 0 in case of error, otherwise
216 * new value of maxptys.
217 */
218 int
219 pty_maxptys(newmax, set)
220 int newmax, set;
221 {
222 if (!set)
223 return (maxptys);
224
225 /* the value cannot be set to value lower than current number of ptys */
226 if (newmax < npty)
227 return (0);
228
229 /* can proceed immediatelly if bigger than current maximum */
230 if (newmax > maxptys) {
231 maxptys = newmax;
232 return (maxptys);
233 }
234
235 /*
236 * We have to grab the pt_softc lock, so that we would pick correct
237 * value of npty (might be modified in check_pty()).
238 */
239 simple_lock(&pt_softc_mutex);
240
241 if (newmax > npty)
242 maxptys = newmax;
243
244 simple_unlock(&pt_softc_mutex);
245
246 return (maxptys);
247 }
248
249 /*
250 * Establish n (or default if n is 1) ptys in the system.
251 */
252 void
253 ptyattach(n)
254 int n;
255 {
256 /* maybe should allow 0 => none? */
257 if (n <= 1)
258 n = DEFAULT_NPTYS;
259 pt_softc = ptyarralloc(n);
260 npty = n;
261 }
262
263 /*ARGSUSED*/
264 int
265 ptsopen(dev, flag, devtype, p)
266 dev_t dev;
267 int flag, devtype;
268 struct proc *p;
269 {
270 struct pt_softc *pti;
271 struct tty *tp;
272 int error;
273
274 if ((error = check_pty(dev)))
275 return (error);
276
277 pti = pt_softc[minor(dev)];
278 tp = pti->pt_tty;
279
280 if (!ISSET(tp->t_state, TS_ISOPEN)) {
281 ttychars(tp); /* Set up default chars */
282 tp->t_iflag = TTYDEF_IFLAG;
283 tp->t_oflag = TTYDEF_OFLAG;
284 tp->t_lflag = TTYDEF_LFLAG;
285 tp->t_cflag = TTYDEF_CFLAG;
286 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
287 ttsetwater(tp); /* would be done in xxparam() */
288 } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
289 return (EBUSY);
290 if (tp->t_oproc) /* Ctrlr still around. */
291 SET(tp->t_state, TS_CARR_ON);
292 if (!ISSET(flag, O_NONBLOCK))
293 while (!ISSET(tp->t_state, TS_CARR_ON)) {
294 tp->t_wopen++;
295 error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
296 ttopen, 0);
297 tp->t_wopen--;
298 if (error)
299 return (error);
300 }
301 error = (*tp->t_linesw->l_open)(dev, tp);
302 ptcwakeup(tp, FREAD|FWRITE);
303 return (error);
304 }
305
306 int
307 ptsclose(dev, flag, mode, p)
308 dev_t dev;
309 int flag, mode;
310 struct proc *p;
311 {
312 struct pt_softc *pti = pt_softc[minor(dev)];
313 struct tty *tp = pti->pt_tty;
314 int error;
315
316 error = (*tp->t_linesw->l_close)(tp, flag);
317 error |= ttyclose(tp);
318 ptcwakeup(tp, FREAD|FWRITE);
319 return (error);
320 }
321
322 int
323 ptsread(dev, uio, flag)
324 dev_t dev;
325 struct uio *uio;
326 int flag;
327 {
328 struct proc *p = curproc->l_proc;
329 struct pt_softc *pti = pt_softc[minor(dev)];
330 struct tty *tp = pti->pt_tty;
331 int error = 0;
332
333 again:
334 if (pti->pt_flags & PF_REMOTE) {
335 while (isbackground(p, tp)) {
336 if (sigismasked(p, SIGTTIN) ||
337 p->p_pgrp->pg_jobc == 0 ||
338 p->p_flag & P_PPWAIT)
339 return (EIO);
340 pgsignal(p->p_pgrp, SIGTTIN, 1);
341 error = ttysleep(tp, (caddr_t)&lbolt,
342 TTIPRI | PCATCH, ttybg, 0);
343 if (error)
344 return (error);
345 }
346 if (tp->t_canq.c_cc == 0) {
347 if (flag & IO_NDELAY)
348 return (EWOULDBLOCK);
349 error = ttysleep(tp, (caddr_t)&tp->t_canq,
350 TTIPRI | PCATCH, ttyin, 0);
351 if (error)
352 return (error);
353 goto again;
354 }
355 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
356 if (ureadc(getc(&tp->t_canq), uio) < 0) {
357 error = EFAULT;
358 break;
359 }
360 if (tp->t_canq.c_cc == 1)
361 (void) getc(&tp->t_canq);
362 if (tp->t_canq.c_cc)
363 return (error);
364 } else
365 if (tp->t_oproc)
366 error = (*tp->t_linesw->l_read)(tp, uio, flag);
367 ptcwakeup(tp, FWRITE);
368 return (error);
369 }
370
371 /*
372 * Write to pseudo-tty.
373 * Wakeups of controlling tty will happen
374 * indirectly, when tty driver calls ptsstart.
375 */
376 int
377 ptswrite(dev, uio, flag)
378 dev_t dev;
379 struct uio *uio;
380 int flag;
381 {
382 struct pt_softc *pti = pt_softc[minor(dev)];
383 struct tty *tp = pti->pt_tty;
384
385 if (tp->t_oproc == 0)
386 return (EIO);
387 return ((*tp->t_linesw->l_write)(tp, uio, flag));
388 }
389
390 /*
391 * Poll pseudo-tty.
392 */
393 int
394 ptspoll(dev, events, p)
395 dev_t dev;
396 int events;
397 struct proc *p;
398 {
399 struct pt_softc *pti = pt_softc[minor(dev)];
400 struct tty *tp = pti->pt_tty;
401
402 if (tp->t_oproc == 0)
403 return (EIO);
404
405 return ((*tp->t_linesw->l_poll)(tp, events, p));
406 }
407
408 /*
409 * Start output on pseudo-tty.
410 * Wake up process polling or sleeping for input from controlling tty.
411 */
412 void
413 ptsstart(tp)
414 struct tty *tp;
415 {
416 struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
417
418 if (ISSET(tp->t_state, TS_TTSTOP))
419 return;
420 if (pti->pt_flags & PF_STOPPED) {
421 pti->pt_flags &= ~PF_STOPPED;
422 pti->pt_send = TIOCPKT_START;
423 }
424 ptcwakeup(tp, FREAD);
425 }
426
427 void
428 ptsstop(tp, flush)
429 struct tty *tp;
430 int flush;
431 {
432 struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
433 int flag;
434
435 /* note: FLUSHREAD and FLUSHWRITE already ok */
436 if (flush == 0) {
437 flush = TIOCPKT_STOP;
438 pti->pt_flags |= PF_STOPPED;
439 } else
440 pti->pt_flags &= ~PF_STOPPED;
441 pti->pt_send |= flush;
442 /* change of perspective */
443 flag = 0;
444 if (flush & FREAD)
445 flag |= FWRITE;
446 if (flush & FWRITE)
447 flag |= FREAD;
448 ptcwakeup(tp, flag);
449 }
450
451 void
452 ptcwakeup(tp, flag)
453 struct tty *tp;
454 int flag;
455 {
456 struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
457
458 if (flag & FREAD) {
459 selwakeup(&pti->pt_selr);
460 wakeup((caddr_t)&tp->t_outq.c_cf);
461 }
462 if (flag & FWRITE) {
463 selwakeup(&pti->pt_selw);
464 wakeup((caddr_t)&tp->t_rawq.c_cf);
465 }
466 }
467
468 /*ARGSUSED*/
469 int
470 ptcopen(dev, flag, devtype, p)
471 dev_t dev;
472 int flag, devtype;
473 struct proc *p;
474 {
475 struct pt_softc *pti;
476 struct tty *tp;
477 int error;
478
479 if ((error = check_pty(dev)))
480 return (error);
481
482 pti = pt_softc[minor(dev)];
483 tp = pti->pt_tty;
484
485 if (tp->t_oproc)
486 return (EIO);
487 tp->t_oproc = ptsstart;
488 (void)(*tp->t_linesw->l_modem)(tp, 1);
489 CLR(tp->t_lflag, EXTPROC);
490 pti->pt_flags = 0;
491 pti->pt_send = 0;
492 pti->pt_ucntl = 0;
493 return (0);
494 }
495
496 /*ARGSUSED*/
497 int
498 ptcclose(dev, flag, devtype, p)
499 dev_t dev;
500 int flag, devtype;
501 struct proc *p;
502 {
503 struct pt_softc *pti = pt_softc[minor(dev)];
504 struct tty *tp = pti->pt_tty;
505
506 (void)(*tp->t_linesw->l_modem)(tp, 0);
507 CLR(tp->t_state, TS_CARR_ON);
508 tp->t_oproc = 0; /* mark closed */
509 return (0);
510 }
511
512 int
513 ptcread(dev, uio, flag)
514 dev_t dev;
515 struct uio *uio;
516 int flag;
517 {
518 struct pt_softc *pti = pt_softc[minor(dev)];
519 struct tty *tp = pti->pt_tty;
520 char buf[BUFSIZ];
521 int error = 0, cc;
522
523 /*
524 * We want to block until the slave
525 * is open, and there's something to read;
526 * but if we lost the slave or we're NBIO,
527 * then return the appropriate error instead.
528 */
529 for (;;) {
530 if (ISSET(tp->t_state, TS_ISOPEN)) {
531 if (pti->pt_flags&PF_PKT && pti->pt_send) {
532 error = ureadc((int)pti->pt_send, uio);
533 if (error)
534 return (error);
535 if (pti->pt_send & TIOCPKT_IOCTL) {
536 cc = min(uio->uio_resid,
537 sizeof(tp->t_termios));
538 uiomove((caddr_t) &tp->t_termios,
539 cc, uio);
540 }
541 pti->pt_send = 0;
542 return (0);
543 }
544 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
545 error = ureadc((int)pti->pt_ucntl, uio);
546 if (error)
547 return (error);
548 pti->pt_ucntl = 0;
549 return (0);
550 }
551 if (tp->t_outq.c_cc && !ISSET(tp->t_state, TS_TTSTOP))
552 break;
553 }
554 if (!ISSET(tp->t_state, TS_CARR_ON))
555 return (0); /* EOF */
556 if (flag & IO_NDELAY)
557 return (EWOULDBLOCK);
558 error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
559 ttyin, 0);
560 if (error)
561 return (error);
562 }
563 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
564 error = ureadc(0, uio);
565 while (uio->uio_resid > 0 && error == 0) {
566 cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
567 if (cc <= 0)
568 break;
569 error = uiomove(buf, cc, uio);
570 }
571 if (tp->t_outq.c_cc <= tp->t_lowat) {
572 if (ISSET(tp->t_state, TS_ASLEEP)) {
573 CLR(tp->t_state, TS_ASLEEP);
574 wakeup((caddr_t)&tp->t_outq);
575 }
576 selwakeup(&tp->t_wsel);
577 }
578 return (error);
579 }
580
581
582 int
583 ptcwrite(dev, uio, flag)
584 dev_t dev;
585 struct uio *uio;
586 int flag;
587 {
588 struct pt_softc *pti = pt_softc[minor(dev)];
589 struct tty *tp = pti->pt_tty;
590 u_char *cp = NULL;
591 int cc = 0;
592 u_char locbuf[BUFSIZ];
593 int cnt = 0;
594 int error = 0;
595
596 again:
597 if (!ISSET(tp->t_state, TS_ISOPEN))
598 goto block;
599 if (pti->pt_flags & PF_REMOTE) {
600 if (tp->t_canq.c_cc)
601 goto block;
602 while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
603 if (cc == 0) {
604 cc = min(uio->uio_resid, BUFSIZ);
605 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
606 cp = locbuf;
607 error = uiomove((caddr_t)cp, cc, uio);
608 if (error)
609 return (error);
610 /* check again for safety */
611 if (!ISSET(tp->t_state, TS_ISOPEN))
612 return (EIO);
613 }
614 if (cc)
615 (void) b_to_q((char *)cp, cc, &tp->t_canq);
616 cc = 0;
617 }
618 (void) putc(0, &tp->t_canq);
619 ttwakeup(tp);
620 wakeup((caddr_t)&tp->t_canq);
621 return (0);
622 }
623 while (uio->uio_resid > 0) {
624 if (cc == 0) {
625 cc = min(uio->uio_resid, BUFSIZ);
626 cp = locbuf;
627 error = uiomove((caddr_t)cp, cc, uio);
628 if (error)
629 return (error);
630 /* check again for safety */
631 if (!ISSET(tp->t_state, TS_ISOPEN))
632 return (EIO);
633 }
634 while (cc > 0) {
635 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
636 (tp->t_canq.c_cc > 0 || !ISSET(tp->t_iflag, ICANON))) {
637 wakeup((caddr_t)&tp->t_rawq);
638 goto block;
639 }
640 (*tp->t_linesw->l_rint)(*cp++, tp);
641 cnt++;
642 cc--;
643 }
644 cc = 0;
645 }
646 return (0);
647 block:
648 /*
649 * Come here to wait for slave to open, for space
650 * in outq, or space in rawq.
651 */
652 if (!ISSET(tp->t_state, TS_CARR_ON))
653 return (EIO);
654 if (flag & IO_NDELAY) {
655 /* adjust for data copied in but not written */
656 uio->uio_resid += cc;
657 if (cnt == 0)
658 return (EWOULDBLOCK);
659 return (0);
660 }
661 error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
662 ttyout, 0);
663 if (error) {
664 /* adjust for data copied in but not written */
665 uio->uio_resid += cc;
666 return (error);
667 }
668 goto again;
669 }
670
671 int
672 ptcpoll(dev, events, p)
673 dev_t dev;
674 int events;
675 struct proc *p;
676 {
677 struct pt_softc *pti = pt_softc[minor(dev)];
678 struct tty *tp = pti->pt_tty;
679 int revents = 0;
680 int s = splsoftclock();
681
682 if (events & (POLLIN | POLLRDNORM))
683 if (ISSET(tp->t_state, TS_ISOPEN) &&
684 ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
685 ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
686 ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
687 revents |= events & (POLLIN | POLLRDNORM);
688
689 if (events & (POLLOUT | POLLWRNORM))
690 if (ISSET(tp->t_state, TS_ISOPEN) &&
691 ((pti->pt_flags & PF_REMOTE) ?
692 (tp->t_canq.c_cc == 0) :
693 ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
694 (tp->t_canq.c_cc == 0 && ISSET(tp->t_iflag, ICANON)))))
695 revents |= events & (POLLOUT | POLLWRNORM);
696
697 if (events & POLLHUP)
698 if (!ISSET(tp->t_state, TS_CARR_ON))
699 revents |= POLLHUP;
700
701 if (revents == 0) {
702 if (events & (POLLIN | POLLHUP | POLLRDNORM))
703 selrecord(p, &pti->pt_selr);
704
705 if (events & (POLLOUT | POLLWRNORM))
706 selrecord(p, &pti->pt_selw);
707 }
708
709 splx(s);
710 return (revents);
711 }
712
713
714 struct tty *
715 ptytty(dev)
716 dev_t dev;
717 {
718 struct pt_softc *pti = pt_softc[minor(dev)];
719 struct tty *tp = pti->pt_tty;
720
721 return (tp);
722 }
723
724 /*ARGSUSED*/
725 int
726 ptyioctl(dev, cmd, data, flag, p)
727 dev_t dev;
728 u_long cmd;
729 caddr_t data;
730 int flag;
731 struct proc *p;
732 {
733 struct pt_softc *pti = pt_softc[minor(dev)];
734 struct tty *tp = pti->pt_tty;
735 u_char *cc = tp->t_cc;
736 int stop, error, sig;
737
738 /*
739 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
740 * ttywflush(tp) will hang if there are characters in the outq.
741 */
742 if (cmd == TIOCEXT) {
743 /*
744 * When the EXTPROC bit is being toggled, we need
745 * to send an TIOCPKT_IOCTL if the packet driver
746 * is turned on.
747 */
748 if (*(int *)data) {
749 if (pti->pt_flags & PF_PKT) {
750 pti->pt_send |= TIOCPKT_IOCTL;
751 ptcwakeup(tp, FREAD);
752 }
753 SET(tp->t_lflag, EXTPROC);
754 } else {
755 if (ISSET(tp->t_lflag, EXTPROC) &&
756 (pti->pt_flags & PF_PKT)) {
757 pti->pt_send |= TIOCPKT_IOCTL;
758 ptcwakeup(tp, FREAD);
759 }
760 CLR(tp->t_lflag, EXTPROC);
761 }
762 return(0);
763 } else
764 if (cdevsw[major(dev)].d_open == ptcopen)
765 switch (cmd) {
766
767 case TIOCGPGRP:
768 #ifdef COMPAT_SUNOS
769 {
770 /*
771 * I'm not sure about SunOS TIOCGPGRP semantics
772 * on PTYs, but it's something like this:
773 */
774 extern struct emul emul_sunos;
775 if (p->p_emul == &emul_sunos && tp->t_pgrp == 0)
776 return (EIO);
777 *(int *)data = tp->t_pgrp->pg_id;
778 return (0);
779 }
780 #endif
781 /*
782 * We avoid calling ttioctl on the controller since,
783 * in that case, tp must be the controlling terminal.
784 */
785 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
786 return (0);
787
788 case TIOCPKT:
789 if (*(int *)data) {
790 if (pti->pt_flags & PF_UCNTL)
791 return (EINVAL);
792 pti->pt_flags |= PF_PKT;
793 } else
794 pti->pt_flags &= ~PF_PKT;
795 return (0);
796
797 case TIOCUCNTL:
798 if (*(int *)data) {
799 if (pti->pt_flags & PF_PKT)
800 return (EINVAL);
801 pti->pt_flags |= PF_UCNTL;
802 } else
803 pti->pt_flags &= ~PF_UCNTL;
804 return (0);
805
806 case TIOCREMOTE:
807 if (*(int *)data)
808 pti->pt_flags |= PF_REMOTE;
809 else
810 pti->pt_flags &= ~PF_REMOTE;
811 ttyflush(tp, FREAD|FWRITE);
812 return (0);
813
814 #ifdef COMPAT_OLDTTY
815 case TIOCSETP:
816 case TIOCSETN:
817 #endif
818 case TIOCSETD:
819 case TIOCSETA:
820 case TIOCSETAW:
821 case TIOCSETAF:
822 ndflush(&tp->t_outq, tp->t_outq.c_cc);
823 break;
824
825 case TIOCSIG:
826 sig = (int)(long)*(caddr_t *)data;
827 if (sig <= 0 || sig >= NSIG)
828 return (EINVAL);
829 if (!ISSET(tp->t_lflag, NOFLSH))
830 ttyflush(tp, FREAD|FWRITE);
831 pgsignal(tp->t_pgrp, sig, 1);
832 if ((sig == SIGINFO) &&
833 (!ISSET(tp->t_lflag, NOKERNINFO)))
834 ttyinfo(tp);
835 return(0);
836 }
837 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
838 if (error < 0)
839 error = ttioctl(tp, cmd, data, flag, p);
840 if (error < 0) {
841 if (pti->pt_flags & PF_UCNTL &&
842 (cmd & ~0xff) == UIOCCMD(0)) {
843 if (cmd & 0xff) {
844 pti->pt_ucntl = (u_char)cmd;
845 ptcwakeup(tp, FREAD);
846 }
847 return (0);
848 }
849 error = ENOTTY;
850 }
851 /*
852 * If external processing and packet mode send ioctl packet.
853 */
854 if (ISSET(tp->t_lflag, EXTPROC) && (pti->pt_flags & PF_PKT)) {
855 switch(cmd) {
856 case TIOCSETA:
857 case TIOCSETAW:
858 case TIOCSETAF:
859 #ifdef COMPAT_OLDTTY
860 case TIOCSETP:
861 case TIOCSETN:
862 case TIOCSETC:
863 case TIOCSLTC:
864 case TIOCLBIS:
865 case TIOCLBIC:
866 case TIOCLSET:
867 #endif
868 pti->pt_send |= TIOCPKT_IOCTL;
869 ptcwakeup(tp, FREAD);
870 default:
871 break;
872 }
873 }
874 stop = ISSET(tp->t_iflag, IXON) && CCEQ(cc[VSTOP], CTRL('s'))
875 && CCEQ(cc[VSTART], CTRL('q'));
876 if (pti->pt_flags & PF_NOSTOP) {
877 if (stop) {
878 pti->pt_send &= ~TIOCPKT_NOSTOP;
879 pti->pt_send |= TIOCPKT_DOSTOP;
880 pti->pt_flags &= ~PF_NOSTOP;
881 ptcwakeup(tp, FREAD);
882 }
883 } else {
884 if (!stop) {
885 pti->pt_send &= ~TIOCPKT_DOSTOP;
886 pti->pt_send |= TIOCPKT_NOSTOP;
887 pti->pt_flags |= PF_NOSTOP;
888 ptcwakeup(tp, FREAD);
889 }
890 }
891 return (error);
892 }
893