xref: /xnu-8796.101.5/bsd/kern/tty_dev.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1 /*
2  * Copyright (c) 1997-2020 Apple 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 /* Common callbacks for the pseudo-teletype driver (pty/tty)
64  * and cloning pseudo-teletype driver (ptmx/pts).
65  */
66 
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/ioctl.h>
70 #include <sys/proc_internal.h>
71 #include <sys/kauth.h>
72 #include <sys/tty.h>
73 #include <sys/conf.h>
74 #include <sys/file_internal.h>
75 #include <sys/uio_internal.h>
76 #include <sys/kernel.h>
77 #include <sys/vnode.h>
78 #include <sys/vnode_internal.h>         /* _devfs_setattr() */
79 #include <sys/stat.h>                   /* _devfs_setattr() */
80 #include <sys/user.h>
81 #include <sys/signalvar.h>
82 #include <sys/sysctl.h>
83 #include <miscfs/devfs/devfs.h>
84 #include <miscfs/devfs/devfsdefs.h>     /* DEVFS_LOCK()/DEVFS_UNLOCK() */
85 #include <dev/kmreg_com.h>
86 
87 #if CONFIG_MACF
88 #include <security/mac_framework.h>
89 #endif
90 
91 #include "tty_dev.h"
92 
93 /* XXX belongs in devfs somewhere - LATER */
94 static int _devfs_setattr(void *, unsigned short, uid_t, gid_t);
95 
96 /*
97  * Forward declarations
98  */
99 static void ptcwakeup(struct tty *tp, int flag);
100 __XNU_PRIVATE_EXTERN    d_open_t        ptsopen;
101 __XNU_PRIVATE_EXTERN    d_close_t       ptsclose;
102 __XNU_PRIVATE_EXTERN    d_read_t        ptsread;
103 __XNU_PRIVATE_EXTERN    d_write_t       ptswrite;
104 __XNU_PRIVATE_EXTERN    d_ioctl_t       ptyioctl;       /* common ioctl */
105 __XNU_PRIVATE_EXTERN    d_stop_t        ptsstop;
106 __XNU_PRIVATE_EXTERN    d_reset_t       ptsreset;
107 __XNU_PRIVATE_EXTERN    d_select_t      ptsselect;
108 __XNU_PRIVATE_EXTERN    d_open_t        ptcopen;
109 __XNU_PRIVATE_EXTERN    d_close_t       ptcclose;
110 __XNU_PRIVATE_EXTERN    d_read_t        ptcread;
111 __XNU_PRIVATE_EXTERN    d_write_t       ptcwrite;
112 __XNU_PRIVATE_EXTERN    d_stop_t        ptcstop;        /* NO-OP */
113 __XNU_PRIVATE_EXTERN    d_reset_t       ptcreset;
114 __XNU_PRIVATE_EXTERN    d_select_t      ptcselect;
115 
116 /*
117  * XXX Should be devfs function... and use VATTR mechanisms, per
118  * XXX vnode_setattr2(); only we maybe can't really get back to the
119  * XXX vnode here for cloning devices (but it works for *cloned* devices
120  * XXX that are not themselves cloning).
121  *
122  * Returns:	0			Success
123  *	namei:???
124  *	vnode_setattr:???
125  */
126 static int
_devfs_setattr(void * handle,unsigned short mode,uid_t uid,gid_t gid)127 _devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid)
128 {
129 	devdirent_t             *direntp = (devdirent_t *)handle;
130 	devnode_t               *devnodep;
131 	int                     error = EACCES;
132 	vfs_context_t           ctx = vfs_context_current();
133 	struct vnode_attr       va;
134 
135 	VATTR_INIT(&va);
136 	VATTR_SET(&va, va_uid, uid);
137 	VATTR_SET(&va, va_gid, gid);
138 	VATTR_SET(&va, va_mode, mode & ALLPERMS);
139 
140 	/*
141 	 * If the TIOCPTYGRANT loses the race with the clone operation because
142 	 * this function is not part of devfs, and therefore can't take the
143 	 * devfs lock to protect the direntp update, then force user space to
144 	 * redrive the grant request.
145 	 */
146 	if (direntp == NULL || (devnodep = direntp->de_dnp) == NULL) {
147 		error = ERESTART;
148 		goto out;
149 	}
150 
151 	/*
152 	 * Only do this if we are operating on device that doesn't clone
153 	 * each time it's referenced.  We perform a lookup on the device
154 	 * to insure we get the right instance.  We can't just use the call
155 	 * to devfs_dntovn() to get the vp for the operation, because
156 	 * dn_dvm may not have been initialized.
157 	 */
158 	if (devnodep->dn_clone == NULL) {
159 		struct nameidata nd;
160 		char name[128];
161 
162 		snprintf(name, sizeof(name), "/dev/%s", direntp->de_name);
163 		NDINIT(&nd, LOOKUP, OP_SETATTR, FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(name), ctx);
164 		error = namei(&nd);
165 		if (error) {
166 			goto out;
167 		}
168 		error = vnode_setattr(nd.ni_vp, &va, ctx);
169 		vnode_put(nd.ni_vp);
170 		nameidone(&nd);
171 		goto out;
172 	}
173 
174 out:
175 	return error;
176 }
177 
178 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
179 
180 static struct tty_dev_t *tty_dev_head;
181 
182 __private_extern__ void
tty_dev_register(struct tty_dev_t * driver)183 tty_dev_register(struct tty_dev_t *driver)
184 {
185 	if (driver) {
186 		driver->next = tty_dev_head;
187 		tty_dev_head = driver;
188 	}
189 }
190 
191 /*
192  * Given a minor number, return the corresponding structure for that minor
193  * number.  If there isn't one, and the create flag is specified, we create
194  * one if possible.
195  *
196  * Parameters:	minor			Minor number of ptmx device
197  *		open_flag		PF_OPEN_M	First open of primary
198  *					PF_OPEN_S	First open of replica
199  *					0		Just want ioctl struct
200  *
201  * Returns:	NULL			Did not exist/could not create
202  *		!NULL			structure corresponding minor number
203  *
204  * Locks:	tty_lock() on ptmx_ioctl->pt_tty NOT held on entry or exit.
205  */
206 
207 static struct tty_dev_t *
pty_get_driver(dev_t dev)208 pty_get_driver(dev_t dev)
209 {
210 	int major = major(dev);
211 	struct tty_dev_t *driver;
212 	for (driver = tty_dev_head; driver != NULL; driver = driver->next) {
213 		if ((driver->primary == major || driver->replica == major)) {
214 			break;
215 		}
216 	}
217 	return driver;
218 }
219 
220 static struct ptmx_ioctl *
pty_get_ioctl(dev_t dev,int open_flag,struct tty_dev_t ** out_driver)221 pty_get_ioctl(dev_t dev, int open_flag, struct tty_dev_t **out_driver)
222 {
223 	struct tty_dev_t *driver = pty_get_driver(dev);
224 	if (out_driver) {
225 		*out_driver = driver;
226 	}
227 	if (driver && driver->open) {
228 		return driver->open(minor(dev), open_flag);
229 	}
230 	return NULL;
231 }
232 
233 /*
234  * Locks:	tty_lock() of old_ptmx_ioctl->pt_tty NOT held for this call.
235  */
236 static int
pty_free_ioctl(dev_t dev,int open_flag)237 pty_free_ioctl(dev_t dev, int open_flag)
238 {
239 	struct tty_dev_t *driver = pty_get_driver(dev);
240 	if (driver && driver->free) {
241 		return driver->free(minor(dev), open_flag);
242 	}
243 	return 0;
244 }
245 
246 static int
pty_get_name(dev_t dev,char * buffer,size_t size)247 pty_get_name(dev_t dev, char *buffer, size_t size)
248 {
249 	struct tty_dev_t *driver = pty_get_driver(dev);
250 	if (driver && driver->name) {
251 		return driver->name(minor(dev), buffer, size);
252 	}
253 	return 0;
254 }
255 
256 __private_extern__ int
ptsopen(dev_t dev,int flag,__unused int devtype,__unused struct proc * p)257 ptsopen(dev_t dev, int flag, __unused int devtype, __unused struct proc *p)
258 {
259 	int error;
260 	struct tty_dev_t *driver;
261 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, PF_OPEN_S, &driver);
262 	if (pti == NULL) {
263 		return ENXIO;
264 	}
265 	if (!(pti->pt_flags & PF_UNLOCKED)) {
266 		return EAGAIN;
267 	}
268 
269 	struct tty *tp = pti->pt_tty;
270 	tty_lock(tp);
271 
272 	if ((tp->t_state & TS_ISOPEN) == 0) {
273 		termioschars(&tp->t_termios);   /* Set up default chars */
274 		tp->t_iflag = TTYDEF_IFLAG;
275 		tp->t_oflag = TTYDEF_OFLAG;
276 		tp->t_lflag = TTYDEF_LFLAG;
277 		tp->t_cflag = TTYDEF_CFLAG;
278 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
279 		ttsetwater(tp);         /* would be done in xxparam() */
280 	} else if ((tp->t_state & TS_XCLUDE) && kauth_cred_issuser(kauth_cred_get())) {
281 		error = EBUSY;
282 		goto out;
283 	}
284 	if (tp->t_oproc) {                      /* Ctrlr still around. */
285 		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
286 	}
287 	while ((tp->t_state & TS_CARR_ON) == 0) {
288 		if (flag & FNONBLOCK) {
289 			break;
290 		}
291 		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, __FUNCTION__, 0);
292 		if (error) {
293 			goto out;
294 		}
295 	}
296 	error = (*linesw[tp->t_line].l_open)(dev, tp);
297 	/* Successful open; mark as open by the replica */
298 
299 	pti->pt_flags |= PF_OPEN_S;
300 	CLR(tp->t_state, TS_IOCTL_NOT_OK);
301 	if (error == 0) {
302 		ptcwakeup(tp, FREAD | FWRITE);
303 	}
304 
305 out:
306 	tty_unlock(tp);
307 	return error;
308 }
309 
310 __private_extern__ int
ptsclose(dev_t dev,int flag,__unused int mode,__unused proc_t p)311 ptsclose(dev_t dev, int flag, __unused int mode, __unused proc_t p)
312 {
313 	int err;
314 
315 	/*
316 	 * This is temporary until the VSX conformance tests
317 	 * are fixed.  They are hanging with a deadlock
318 	 * where close() will not complete without t_timeout set
319 	 */
320 #define FIX_VSX_HANG    1
321 #ifdef  FIX_VSX_HANG
322 	int save_timeout;
323 #endif
324 	struct tty_dev_t *driver;
325 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
326 	struct tty *tp;
327 
328 	if (pti == NULL) {
329 		return ENXIO;
330 	}
331 
332 	tp = pti->pt_tty;
333 	tty_lock(tp);
334 #ifdef  FIX_VSX_HANG
335 	save_timeout = tp->t_timeout;
336 	tp->t_timeout = 60;
337 #endif
338 	/*
339 	 * Close the line discipline and backing TTY structures.
340 	 */
341 	err = (*linesw[tp->t_line].l_close)(tp, flag);
342 	(void)ttyclose(tp);
343 
344 	/*
345 	 * Flush data and notify any waiters on the primary side of this PTY.
346 	 */
347 	ptsstop(tp, FREAD | FWRITE);
348 #ifdef  FIX_VSX_HANG
349 	tp->t_timeout = save_timeout;
350 #endif
351 	tty_unlock(tp);
352 
353 	if ((flag & IO_REVOKE) == IO_REVOKE && driver->revoke) {
354 		driver->revoke(minor(dev), tp);
355 	}
356 	/* unconditional, just like ttyclose() */
357 	pty_free_ioctl(dev, PF_OPEN_S);
358 
359 	return err;
360 }
361 
362 __private_extern__ int
ptsread(dev_t dev,struct uio * uio,int flag)363 ptsread(dev_t dev, struct uio *uio, int flag)
364 {
365 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
366 	struct tty *tp;
367 	int error = 0;
368 	struct uthread *ut;
369 
370 	if (pti == NULL) {
371 		return ENXIO;
372 	}
373 	tp = pti->pt_tty;
374 	tty_lock(tp);
375 
376 	ut = current_uthread();
377 	if (tp->t_oproc) {
378 		error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
379 	}
380 	ptcwakeup(tp, FWRITE);
381 	tty_unlock(tp);
382 	return error;
383 }
384 
385 /*
386  * Write to pseudo-tty.
387  * Wakeups of controlling tty will happen
388  * indirectly, when tty driver calls ptsstart.
389  */
390 __private_extern__ int
ptswrite(dev_t dev,struct uio * uio,int flag)391 ptswrite(dev_t dev, struct uio *uio, int flag)
392 {
393 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
394 	struct tty *tp;
395 	int error;
396 
397 	if (pti == NULL) {
398 		return ENXIO;
399 	}
400 	tp = pti->pt_tty;
401 	tty_lock(tp);
402 
403 	if (tp->t_oproc == 0) {
404 		error = EIO;
405 	} else {
406 		error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
407 	}
408 
409 	tty_unlock(tp);
410 
411 	return error;
412 }
413 
414 /*
415  * Start output on pseudo-tty.
416  * Wake up process selecting or sleeping for input from controlling tty.
417  *
418  * t_oproc for this driver; called from within the line discipline
419  *
420  * Locks:	Assumes tp is locked on entry, remains locked on exit
421  */
422 static void
ptsstart(struct tty * tp)423 ptsstart(struct tty *tp)
424 {
425 	struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
426 	if (pti == NULL) {
427 		goto out;
428 	}
429 	if (tp->t_state & TS_TTSTOP) {
430 		goto out;
431 	}
432 	if (pti->pt_flags & PF_STOPPED) {
433 		pti->pt_flags &= ~PF_STOPPED;
434 		pti->pt_send = TIOCPKT_START;
435 	}
436 	ptcwakeup(tp, FREAD);
437 out:
438 	return;
439 }
440 
441 static void
ptcwakeup_knote(struct selinfo * sip,long hint)442 ptcwakeup_knote(struct selinfo *sip, long hint)
443 {
444 	if ((sip->si_flags & SI_KNPOSTING) == 0) {
445 		sip->si_flags |= SI_KNPOSTING;
446 		KNOTE(&sip->si_note, hint);
447 		sip->si_flags &= ~SI_KNPOSTING;
448 	}
449 }
450 
451 /*
452  * Locks:	Assumes tty_lock() is held over this call.
453  */
454 static void
ptcwakeup(struct tty * tp,int flag)455 ptcwakeup(struct tty *tp, int flag)
456 {
457 	struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
458 	if (pti == NULL) {
459 		return;
460 	}
461 
462 	if (flag & FREAD) {
463 		selwakeup(&pti->pt_selr);
464 		wakeup(TSA_PTC_READ(tp));
465 		ptcwakeup_knote(&pti->pt_selr, 1);
466 	}
467 	if (flag & FWRITE) {
468 		selwakeup(&pti->pt_selw);
469 		wakeup(TSA_PTC_WRITE(tp));
470 		ptcwakeup_knote(&pti->pt_selw, 1);
471 	}
472 }
473 
474 __private_extern__ int
ptcopen(dev_t dev,__unused int flag,__unused int devtype,__unused proc_t p)475 ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p)
476 {
477 	struct tty_dev_t *driver;
478 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, PF_OPEN_M, &driver);
479 	if (pti == NULL) {
480 		return ENXIO;
481 	} else if (pti == (struct ptmx_ioctl*)-1) {
482 		return EREDRIVEOPEN;
483 	}
484 
485 	struct tty *tp = pti->pt_tty;
486 	tty_lock(tp);
487 
488 	/* If primary is open OR replica is still draining, pty is still busy */
489 	if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) {
490 		tty_unlock(tp);
491 		/*
492 		 * If primary is closed, we are the only reference, so we
493 		 * need to clear the primary open bit
494 		 */
495 		if (!tp->t_oproc) {
496 			pty_free_ioctl(dev, PF_OPEN_M);
497 		}
498 		return EBUSY;
499 	}
500 	tp->t_oproc = ptsstart;
501 	CLR(tp->t_state, TS_ZOMBIE);
502 	SET(tp->t_state, TS_IOCTL_NOT_OK);
503 #ifdef sun4c
504 	tp->t_stop = ptsstop;
505 #endif
506 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
507 	tp->t_lflag &= ~EXTPROC;
508 
509 	if (driver->open_reset) {
510 		pti->pt_flags = PF_UNLOCKED;
511 		pti->pt_send = 0;
512 		pti->pt_ucntl = 0;
513 	}
514 
515 	tty_unlock(tp);
516 	return 0;
517 }
518 
519 __private_extern__ int
ptcclose(dev_t dev,__unused int flags,__unused int fmt,__unused proc_t p)520 ptcclose(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p)
521 {
522 	struct tty_dev_t *driver;
523 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
524 	struct tty *tp;
525 	struct knote *kn;
526 
527 	if (!pti) {
528 		return ENXIO;
529 	}
530 
531 	tp = pti->pt_tty;
532 	tty_lock(tp);
533 
534 	/*
535 	 * XXX MDMBUF makes no sense for PTYs, but would inhibit an `l_modem`.
536 	 * CLOCAL makes sense but isn't supported.  Special `l_modem`s that ignore
537 	 * carrier drop make no sense for PTYs but may be in use because other parts
538 	 * of the line discipline make sense for PTYs.  Recover by doing everything
539 	 * that a normal `ttymodem` would have done except for sending SIGHUP.
540 	 */
541 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
542 	if (tp->t_state & TS_ISOPEN) {
543 		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
544 		tp->t_state |= TS_ZOMBIE;
545 		ttyflush(tp, FREAD | FWRITE);
546 	}
547 
548 	/*
549 	 * Null out the backing TTY struct's open procedure to prevent starting
550 	 * replicas through `ptsstart`.
551 	 */
552 	tp->t_oproc = NULL;
553 
554 	/*
555 	 * Clear any select or kevent waiters under the lock.
556 	 */
557 	SLIST_FOREACH(kn, &pti->pt_selr.si_note, kn_selnext) {
558 		KNOTE_DETACH(&pti->pt_selr.si_note, kn);
559 	}
560 	selthreadclear(&pti->pt_selr);
561 	SLIST_FOREACH(kn, &pti->pt_selw.si_note, kn_selnext) {
562 		KNOTE_DETACH(&pti->pt_selw.si_note, kn);
563 	}
564 	selthreadclear(&pti->pt_selw);
565 
566 	tty_unlock(tp);
567 
568 	pty_free_ioctl(dev, PF_OPEN_M);
569 #if CONFIG_MACF
570 	if (driver->mac_notify) {
571 		mac_pty_notify_close(p, tp, dev, NULL);
572 	}
573 #endif
574 
575 	return 0;
576 }
577 
578 __private_extern__ int
ptcread(dev_t dev,struct uio * uio,int flag)579 ptcread(dev_t dev, struct uio *uio, int flag)
580 {
581 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
582 	struct tty *tp;
583 	char buf[BUFSIZ];
584 	int error = 0, cc;
585 
586 	if (pti == NULL) {
587 		return ENXIO;
588 	}
589 	tp = pti->pt_tty;
590 	tty_lock(tp);
591 
592 	/*
593 	 * We want to block until the replica
594 	 * is open, and there's something to read;
595 	 * but if we lost the replica or we're NBIO,
596 	 * then return the appropriate error instead.
597 	 */
598 	for (;;) {
599 		if (tp->t_state & TS_ISOPEN) {
600 			if (pti->pt_flags & PF_PKT && pti->pt_send) {
601 				error = ureadc((int)pti->pt_send, uio);
602 				if (error) {
603 					goto out;
604 				}
605 				if (pti->pt_send & TIOCPKT_IOCTL) {
606 #ifdef __LP64__
607 					if (uio->uio_segflg == UIO_USERSPACE32) {
608 						static struct termios32 tio32;
609 						cc = MIN((int)uio_resid(uio), (int)sizeof(tio32));
610 						termios64to32((struct user_termios *)&tp->t_termios,
611 						    (struct termios32 *)&tio32);
612 						uiomove((caddr_t)&tio32, cc, uio);
613 #else
614 					if (uio->uio_segflg == UIO_USERSPACE64) {
615 						static struct user_termios tio64;
616 						cc = MIN((int)uio_resid(uio), (int)sizeof(tio64));
617 						termios32to64((struct termios32 *)&tp->t_termios,
618 						    (struct user_termios *)&tio64);
619 						uiomove((caddr_t)&tio64, cc, uio);
620 #endif
621 					} else {
622 						cc = MIN((int)uio_resid(uio), (int)sizeof(tp->t_termios));
623 						uiomove((caddr_t)&tp->t_termios, cc, uio);
624 					}
625 				}
626 				pti->pt_send = 0;
627 				goto out;
628 			}
629 			if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
630 				error = ureadc((int)pti->pt_ucntl, uio);
631 				if (error) {
632 					goto out;
633 				}
634 				pti->pt_ucntl = 0;
635 				goto out;
636 			}
637 			if (tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) {
638 				break;
639 			}
640 		}
641 		if ((tp->t_state & TS_CONNECTED) == 0) {
642 			goto out;       /* EOF */
643 		}
644 		if (flag & IO_NDELAY) {
645 			error = EWOULDBLOCK;
646 			goto out;
647 		}
648 		error = ttysleep(tp, TSA_PTC_READ(tp), TTIPRI | PCATCH, __FUNCTION__, 0);
649 		if (error) {
650 			goto out;
651 		}
652 	}
653 	if (pti->pt_flags & (PF_PKT | PF_UCNTL)) {
654 		error = ureadc(0, uio);
655 	}
656 	while (uio_resid(uio) > 0 && error == 0) {
657 		cc = q_to_b(&tp->t_outq, (u_char *)buf, MIN((int)uio_resid(uio), BUFSIZ));
658 		if (cc <= 0) {
659 			break;
660 		}
661 		error = uiomove(buf, cc, uio);
662 	}
663 	(*linesw[tp->t_line].l_start)(tp);
664 
665 out:
666 	tty_unlock(tp);
667 
668 	return error;
669 }
670 
671 /*
672  * Line discipline callback
673  *
674  * Locks:	tty_lock() is assumed held on entry and exit.
675  */
676 __private_extern__ int
677 ptsstop(struct tty* tp, int flush)
678 {
679 	struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
680 	int flag;
681 
682 	if (pti == NULL) {
683 		return ENXIO;
684 	}
685 
686 	/* note: FLUSHREAD and FLUSHWRITE already ok */
687 	if (flush == 0) {
688 		flush = TIOCPKT_STOP;
689 		pti->pt_flags |= PF_STOPPED;
690 	} else {
691 		pti->pt_flags &= ~PF_STOPPED;
692 	}
693 	pti->pt_send |= flush;
694 	/* change of perspective */
695 	flag = 0;
696 	if (flush & FREAD) {
697 		flag |= FWRITE;
698 	}
699 	if (flush & FWRITE) {
700 		flag |= FREAD;
701 	}
702 	ptcwakeup(tp, flag);
703 	return 0;
704 }
705 
706 __private_extern__ int
707 ptsreset(__unused int uban)
708 {
709 	return 0;
710 }
711 
712 int
713 ptsselect(dev_t dev, int rw, void *wql, proc_t p)
714 {
715 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
716 	struct tty *tp;
717 	int retval = 0;
718 
719 	if (pti == NULL) {
720 		return ENXIO;
721 	}
722 	tp = pti->pt_tty;
723 	if (tp == NULL) {
724 		return ENXIO;
725 	}
726 
727 	tty_lock(tp);
728 
729 	switch (rw) {
730 	case FREAD:
731 		if (ISSET(tp->t_state, TS_ZOMBIE)) {
732 			retval = 1;
733 			break;
734 		}
735 
736 		retval = ttnread(tp);
737 		if (retval > 0) {
738 			break;
739 		}
740 
741 		selrecord(p, &tp->t_rsel, wql);
742 		break;
743 	case FWRITE:
744 		if (ISSET(tp->t_state, TS_ZOMBIE)) {
745 			retval = 1;
746 			break;
747 		}
748 
749 		if ((tp->t_outq.c_cc <= tp->t_lowat) &&
750 		    ISSET(tp->t_state, TS_CONNECTED)) {
751 			retval = tp->t_hiwat - tp->t_outq.c_cc;
752 			break;
753 		}
754 
755 		selrecord(p, &tp->t_wsel, wql);
756 		break;
757 	}
758 
759 	tty_unlock(tp);
760 	return retval;
761 }
762 
763 __private_extern__ int
764 ptcselect(dev_t dev, int rw, void *wql, proc_t p)
765 {
766 	struct tty_dev_t *driver;
767 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
768 	struct tty *tp;
769 	int retval = 0;
770 
771 	if (pti == NULL) {
772 		return ENXIO;
773 	}
774 	tp = pti->pt_tty;
775 	tty_lock(tp);
776 
777 	if ((tp->t_state & TS_CONNECTED) == 0) {
778 		retval = 1;
779 		goto out;
780 	}
781 	switch (rw) {
782 	case FREAD:
783 		/*
784 		 * Need to block timeouts (ttrstart).
785 		 */
786 		if ((tp->t_state & TS_ISOPEN) &&
787 		    tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) {
788 			retval = (driver->fix_7828447) ? tp->t_outq.c_cc : 1;
789 			break;
790 		}
791 		OS_FALLTHROUGH;
792 
793 	case 0: /* exceptional */
794 		if ((tp->t_state & TS_ISOPEN) &&
795 		    (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
796 		    ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))) {
797 			retval = 1;
798 			break;
799 		}
800 		selrecord(p, &pti->pt_selr, wql);
801 		break;
802 
803 
804 	case FWRITE:
805 		if (tp->t_state & TS_ISOPEN) {
806 			retval = (TTYHOG - 2) - (tp->t_rawq.c_cc + tp->t_canq.c_cc);
807 			if (retval > 0) {
808 				retval = (driver->fix_7828447) ? retval : 1;
809 				break;
810 			}
811 			if (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)) {
812 				retval = 1;
813 				break;
814 			}
815 			retval = 0;
816 		}
817 		selrecord(p, &pti->pt_selw, wql);
818 		break;
819 	}
820 out:
821 	tty_unlock(tp);
822 
823 	return retval;
824 }
825 
826 __private_extern__ int
827 ptcstop(__unused struct tty *tp, __unused int flush)
828 {
829 	return 0;
830 }
831 
832 __private_extern__ int
833 ptcreset(__unused int uban)
834 {
835 	return 0;
836 }
837 
838 __private_extern__ int
839 ptcwrite(dev_t dev, struct uio *uio, int flag)
840 {
841 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
842 	struct tty *tp;
843 	u_char *cp = NULL;
844 	int cc = 0;
845 	u_char locbuf[BUFSIZ];
846 	int wcnt = 0;
847 	int error = 0;
848 
849 	if (pti == NULL) {
850 		return ENXIO;
851 	}
852 	tp = pti->pt_tty;
853 	tty_lock(tp);
854 
855 again:
856 	if ((tp->t_state & TS_ISOPEN) == 0) {
857 		goto block;
858 	}
859 	while (uio_resid(uio) > 0 || cc > 0) {
860 		if (cc == 0) {
861 			cc = MIN((int)uio_resid(uio), BUFSIZ);
862 			cp = locbuf;
863 			error = uiomove((caddr_t)cp, cc, uio);
864 			if (error) {
865 				goto out;
866 			}
867 			/* check again for safety */
868 			if ((tp->t_state & TS_ISOPEN) == 0) {
869 				/* adjust for data copied in but not written */
870 				uio_setresid(uio, (uio_resid(uio) + cc));
871 				error = EIO;
872 				goto out;
873 			}
874 		}
875 		while (cc > 0) {
876 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
877 			    (tp->t_canq.c_cc > 0 || !(tp->t_lflag & ICANON))) {
878 				wakeup(TSA_HUP_OR_INPUT(tp));
879 				goto block;
880 			}
881 			OS_ANALYZER_SUPPRESS("80961525") (*linesw[tp->t_line].l_rint)(*cp++, tp);
882 			wcnt++;
883 			cc--;
884 		}
885 		cc = 0;
886 	}
887 out:
888 	tty_unlock(tp);
889 
890 	return error;
891 
892 block:
893 	/*
894 	 * Come here to wait for replica to open, for space
895 	 * in outq, or space in rawq, or an empty canq.
896 	 */
897 	if ((tp->t_state & TS_CONNECTED) == 0) {
898 		/* adjust for data copied in but not written */
899 		uio_setresid(uio, (uio_resid(uio) + cc));
900 		error = EIO;
901 		goto out;
902 	}
903 	if (flag & IO_NDELAY) {
904 		/* adjust for data copied in but not written */
905 		uio_setresid(uio, (uio_resid(uio) + cc));
906 		if (wcnt == 0) {
907 			error = EWOULDBLOCK;
908 		}
909 		goto out;
910 	}
911 	error = ttysleep(tp, TSA_PTC_WRITE(tp), TTOPRI | PCATCH, __FUNCTION__, 0);
912 	if (error) {
913 		/* adjust for data copied in but not written */
914 		uio_setresid(uio, (uio_resid(uio) + cc));
915 		goto out;
916 	}
917 	goto again;
918 }
919 
920 /*
921  * ptyioctl: Assumes dev was opened and lock was initilized
922  */
923 __private_extern__ int
924 ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
925 {
926 	struct tty_dev_t *driver;
927 	struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
928 	struct tty *tp;
929 	int stop, error = 0;
930 	int allow_ext_ioctl = 1;
931 
932 	if (pti == NULL || pti->pt_tty == NULL) {
933 		return ENXIO;
934 	}
935 
936 	if (cmd == KMIOCDISABLCONS) {
937 		return 0;
938 	}
939 
940 	tp = pti->pt_tty;
941 	tty_lock(tp);
942 
943 	u_char *cc = tp->t_cc;
944 
945 	/*
946 	 * Do not permit extended ioctls on the primary side of the pty unless
947 	 * the replica side has been successfully opened and initialized.
948 	 */
949 	if (major(dev) == driver->primary &&
950 	    driver->fix_7070978 &&
951 	    ISSET(tp->t_state, TS_IOCTL_NOT_OK)) {
952 		allow_ext_ioctl = 0;
953 	}
954 
955 	/*
956 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
957 	 * ttywflush(tp) will hang if there are characters in the outq.
958 	 */
959 	if (cmd == TIOCEXT && allow_ext_ioctl) {
960 		/*
961 		 * When the EXTPROC bit is being toggled, we need
962 		 * to send an TIOCPKT_IOCTL if the packet driver
963 		 * is turned on.
964 		 */
965 		if (*(int *)data) {
966 			if (pti->pt_flags & PF_PKT) {
967 				pti->pt_send |= TIOCPKT_IOCTL;
968 				ptcwakeup(tp, FREAD);
969 			}
970 			tp->t_lflag |= EXTPROC;
971 		} else {
972 			if ((tp->t_lflag & EXTPROC) &&
973 			    (pti->pt_flags & PF_PKT)) {
974 				pti->pt_send |= TIOCPKT_IOCTL;
975 				ptcwakeup(tp, FREAD);
976 			}
977 			tp->t_lflag &= ~EXTPROC;
978 		}
979 		goto out;
980 	} else if (cdevsw[major(dev)].d_open == ptcopen) {
981 		switch (cmd) {
982 		case TIOCGPGRP:
983 			/*
984 			 * We aviod calling ttioctl on the controller since,
985 			 * in that case, tp must be the controlling terminal.
986 			 */
987 			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
988 			goto out;
989 
990 		case TIOCPKT:
991 			if (*(int *)data) {
992 				if (pti->pt_flags & PF_UCNTL) {
993 					error = EINVAL;
994 					goto out;
995 				}
996 				pti->pt_flags |= PF_PKT;
997 			} else {
998 				pti->pt_flags &= ~PF_PKT;
999 			}
1000 			goto out;
1001 
1002 		case TIOCUCNTL:
1003 			if (*(int *)data) {
1004 				if (pti->pt_flags & PF_PKT) {
1005 					error = EINVAL;
1006 					goto out;
1007 				}
1008 				pti->pt_flags |= PF_UCNTL;
1009 			} else {
1010 				pti->pt_flags &= ~PF_UCNTL;
1011 			}
1012 			goto out;
1013 
1014 		case TIOCSETP:
1015 		case TIOCSETN:
1016 		case TIOCSETD:
1017 		case TIOCSETA_32:
1018 		case TIOCSETAW_32:
1019 		case TIOCSETAF_32:
1020 		case TIOCSETA_64:
1021 		case TIOCSETAW_64:
1022 		case TIOCSETAF_64:
1023 			ndflush(&tp->t_outq, tp->t_outq.c_cc);
1024 			break;
1025 
1026 		case TIOCSIG:
1027 			if (*(unsigned int *)data >= NSIG ||
1028 			    *(unsigned int *)data == 0) {
1029 				error = EINVAL;
1030 				goto out;
1031 			}
1032 			if ((tp->t_lflag & NOFLSH) == 0) {
1033 				ttyflush(tp, FREAD | FWRITE);
1034 			}
1035 			if ((*(unsigned int *)data == SIGINFO) &&
1036 			    ((tp->t_lflag & NOKERNINFO) == 0)) {
1037 				ttyinfo_locked(tp);
1038 			}
1039 			/*
1040 			 * SAFE: All callers drop the lock on return and
1041 			 * SAFE: the linesw[] will short circut this call
1042 			 * SAFE: if the ioctl() is eaten before the lower
1043 			 * SAFE: level code gets to see it.
1044 			 */
1045 			tty_pgsignal_locked(tp, *(unsigned int *)data, 1);
1046 			goto out;
1047 
1048 		case TIOCPTYGRANT:      /* grantpt(3) */
1049 			/*
1050 			 * Change the uid of the replica to that of the calling
1051 			 * thread, change the gid of the replica to GID_TTY,
1052 			 * change the mode to 0620 (rw--w----).
1053 			 */
1054 		{
1055 			error = _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY);
1056 			if (major(dev) == driver->primary) {
1057 				if (driver->mac_notify) {
1058 #if CONFIG_MACF
1059 					if (!error) {
1060 						tty_unlock(tp);
1061 						mac_pty_notify_grant(p, tp, dev, NULL);
1062 						tty_lock(tp);
1063 					}
1064 #endif
1065 				} else {
1066 					error = 0;
1067 				}
1068 			}
1069 			goto out;
1070 		}
1071 
1072 		case TIOCPTYGNAME:      /* ptsname(3) */
1073 			/*
1074 			 * Report the name of the replica device in *data
1075 			 * (128 bytes max.).  Use the same template string
1076 			 * used for calling devfs_make_node() to create it.
1077 			 */
1078 			pty_get_name(dev, data, 128);
1079 			error = 0;
1080 			goto out;
1081 
1082 		case TIOCPTYUNLK:       /* unlockpt(3) */
1083 			/*
1084 			 * Unlock the replica device so that it can be opened.
1085 			 */
1086 			if (major(dev) == driver->primary) {
1087 				pti->pt_flags |= PF_UNLOCKED;
1088 			}
1089 			error = 0;
1090 			goto out;
1091 		}
1092 
1093 		/*
1094 		 * Fail all other calls; pty primaries are not serial devices;
1095 		 * we only pretend they are when the replica side of the pty is
1096 		 * already open.
1097 		 */
1098 		if (!allow_ext_ioctl) {
1099 			error = ENOTTY;
1100 			goto out;
1101 		}
1102 	}
1103 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1104 	if (error == ENOTTY) {
1105 		error = ttioctl_locked(tp, cmd, data, flag, p);
1106 		if (error == ENOTTY) {
1107 			if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) {
1108 				/* Process the UIOCMD ioctl group */
1109 				if (cmd & 0xff) {
1110 					pti->pt_ucntl = (u_char)cmd;
1111 					ptcwakeup(tp, FREAD);
1112 				}
1113 				error = 0;
1114 				goto out;
1115 			} else if (cmd == TIOCSBRK || cmd == TIOCCBRK) {
1116 				/*
1117 				 * POSIX conformance; rdar://3936338
1118 				 *
1119 				 * Clear ENOTTY in the case of setting or
1120 				 * clearing a break failing because pty's
1121 				 * don't support break like real serial
1122 				 * ports.
1123 				 */
1124 				error = 0;
1125 				goto out;
1126 			}
1127 		}
1128 	}
1129 
1130 	/*
1131 	 * If external processing and packet mode send ioctl packet.
1132 	 */
1133 	if ((tp->t_lflag & EXTPROC) && (pti->pt_flags & PF_PKT)) {
1134 		switch (cmd) {
1135 		case TIOCSETA_32:
1136 		case TIOCSETAW_32:
1137 		case TIOCSETAF_32:
1138 		case TIOCSETA_64:
1139 		case TIOCSETAW_64:
1140 		case TIOCSETAF_64:
1141 		case TIOCSETP:
1142 		case TIOCSETN:
1143 		case TIOCSETC:
1144 		case TIOCSLTC:
1145 		case TIOCLBIS:
1146 		case TIOCLBIC:
1147 		case TIOCLSET:
1148 			pti->pt_send |= TIOCPKT_IOCTL;
1149 			ptcwakeup(tp, FREAD);
1150 			break;
1151 		default:
1152 			break;
1153 		}
1154 	}
1155 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
1156 	    && CCEQ(cc[VSTART], CTRL('q'));
1157 	if (pti->pt_flags & PF_NOSTOP) {
1158 		if (stop) {
1159 			pti->pt_send &= ~TIOCPKT_NOSTOP;
1160 			pti->pt_send |= TIOCPKT_DOSTOP;
1161 			pti->pt_flags &= ~PF_NOSTOP;
1162 			ptcwakeup(tp, FREAD);
1163 		}
1164 	} else {
1165 		if (!stop) {
1166 			pti->pt_send &= ~TIOCPKT_DOSTOP;
1167 			pti->pt_send |= TIOCPKT_NOSTOP;
1168 			pti->pt_flags |= PF_NOSTOP;
1169 			ptcwakeup(tp, FREAD);
1170 		}
1171 	}
1172 out:
1173 	tty_unlock(tp);
1174 
1175 	return error;
1176 }
1177