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
88typedef void d_stop_t(struct tty *tp, int rw);
89
90/* XXX function should be removed??? */
91int pty_init(int n_ptys);
92
93/* XXX should be a devfs function */
94int _devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid);
95
96static void ptsstart(struct tty *tp);
97static 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
127static 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 */
134static 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
143int
144pty_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
152int
153pty_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
178ptsopen(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
231out:
232	tty_unlock(tp);
233err:
234	return (error);
235}
236
237__private_extern__ int
238ptsclose(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
270ptsread(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());
282again:
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);
349out:
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
360ptswrite(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 */
387static void
388ptsstart(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);
399out:
400	return;
401}
402
403/*
404 * Locks:	Assumes tty_lock() is held over this call.
405 */
406static void
407ptcwakeup(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
422ptcopen(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
458out:
459	return (error);
460}
461
462__private_extern__ int
463ptcclose(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
493ptcread(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
553out:
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
565ptsstop(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
589ptcselect(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	}
647out:
648	tty_unlock(tp);
649
650	return (retval);
651}
652
653__private_extern__ int
654ptcwrite(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
666again:
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	}
737out:
738	tty_unlock(tp);
739
740	return (error);
741
742block:
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
770ptyioctl(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	}
978out:
979	tty_unlock(tp);
980
981	return (error);
982}
983