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