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