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