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