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 struct tty *constty = NULL;
535 struct tty *freetp = NULL;
536
537 if (!pti) {
538 return ENXIO;
539 }
540
541 tp = pti->pt_tty;
542 tty_lock(tp);
543
544 constty = copy_constty();
545
546 if (constty == tp) {
547 freetp = set_constty(NULL);
548 if (freetp != NULL) {
549 if (freetp == tp) {
550 ttyfree_locked(freetp);
551 } else {
552 ttyfree(freetp);
553 }
554 freetp = NULL;
555 }
556
557
558
559 /*
560 * Closing current console tty; disable printing of console
561 * messages at bottom-level driver.
562 */
563 (*cdevsw[major(tp->t_dev)].d_ioctl)
564 (tp->t_dev, KMIOCDISABLCONS, NULL, 0, current_proc());
565 }
566
567 if (constty != NULL) {
568 if (constty == tp) {
569 ttyfree_locked(constty);
570 } else {
571 ttyfree(constty);
572 }
573 constty = NULL;
574 }
575
576 /*
577 * XXX MDMBUF makes no sense for PTYs, but would inhibit an `l_modem`.
578 * CLOCAL makes sense but isn't supported. Special `l_modem`s that ignore
579 * carrier drop make no sense for PTYs but may be in use because other parts
580 * of the line discipline make sense for PTYs. Recover by doing everything
581 * that a normal `ttymodem` would have done except for sending SIGHUP.
582 */
583 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
584 if (tp->t_state & TS_ISOPEN) {
585 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
586 tp->t_state |= TS_ZOMBIE;
587 ttyflush(tp, FREAD | FWRITE);
588 }
589
590 /*
591 * Null out the backing TTY struct's open procedure to prevent starting
592 * replicas through `ptsstart`.
593 */
594 tp->t_oproc = NULL;
595
596 /*
597 * Clear any select or kevent waiters under the lock.
598 */
599 knote(&pti->pt_selr.si_note, NOTE_REVOKE, true);
600 selthreadclear(&pti->pt_selr);
601 knote(&pti->pt_selw.si_note, NOTE_REVOKE, true);
602 selthreadclear(&pti->pt_selw);
603
604 tty_unlock(tp);
605
606 #if CONFIG_MACF
607 if (driver->mac_notify) {
608 mac_pty_notify_close(p, tp, dev, NULL);
609 }
610 #endif
611 pty_free_ioctl(dev, PF_OPEN_M);
612
613 return 0;
614 }
615
616 __private_extern__ int
ptcread(dev_t dev,struct uio * uio,int flag)617 ptcread(dev_t dev, struct uio *uio, int flag)
618 {
619 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
620 struct tty *tp;
621 char buf[BUFSIZ];
622 int error = 0, cc;
623
624 if (pti == NULL) {
625 return ENXIO;
626 }
627 tp = pti->pt_tty;
628 tty_lock(tp);
629
630 /*
631 * We want to block until the replica
632 * is open, and there's something to read;
633 * but if we lost the replica or we're NBIO,
634 * then return the appropriate error instead.
635 */
636 for (;;) {
637 if (tp->t_state & TS_ISOPEN) {
638 if (pti->pt_flags & PF_PKT && pti->pt_send) {
639 error = ureadc((int)pti->pt_send, uio);
640 if (error) {
641 goto out;
642 }
643 if (pti->pt_send & TIOCPKT_IOCTL) {
644 #ifdef __LP64__
645 if (uio->uio_segflg == UIO_USERSPACE32) {
646 static struct termios32 tio32;
647 cc = MIN((int)uio_resid(uio), (int)sizeof(tio32));
648 termios64to32((struct user_termios *)&tp->t_termios,
649 (struct termios32 *)&tio32);
650 uiomove((caddr_t)&tio32, cc, uio);
651 #else
652 if (uio->uio_segflg == UIO_USERSPACE64) {
653 static struct user_termios tio64;
654 cc = MIN((int)uio_resid(uio), (int)sizeof(tio64));
655 termios32to64((struct termios32 *)&tp->t_termios,
656 (struct user_termios *)&tio64);
657 uiomove((caddr_t)&tio64, cc, uio);
658 #endif
659 } else {
660 cc = MIN((int)uio_resid(uio), (int)sizeof(tp->t_termios));
661 uiomove((caddr_t)&tp->t_termios, cc, uio);
662 }
663 }
664 pti->pt_send = 0;
665 goto out;
666 }
667 if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
668 error = ureadc((int)pti->pt_ucntl, uio);
669 if (error) {
670 goto out;
671 }
672 pti->pt_ucntl = 0;
673 goto out;
674 }
675 if (tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) {
676 break;
677 }
678 }
679 if ((tp->t_state & TS_CONNECTED) == 0) {
680 goto out; /* EOF */
681 }
682 if (flag & IO_NDELAY) {
683 error = EWOULDBLOCK;
684 goto out;
685 }
686 error = ttysleep(tp, TSA_PTC_READ(tp), TTIPRI | PCATCH, __FUNCTION__, 0);
687 if (error) {
688 goto out;
689 }
690 }
691 if (pti->pt_flags & (PF_PKT | PF_UCNTL)) {
692 error = ureadc(0, uio);
693 }
694 while (uio_resid(uio) > 0 && error == 0) {
695 cc = q_to_b(&tp->t_outq, (u_char *)buf, MIN((int)uio_resid(uio), BUFSIZ));
696 if (cc <= 0) {
697 break;
698 }
699 error = uiomove(buf, cc, uio);
700 }
701 (*linesw[tp->t_line].l_start)(tp);
702
703 out:
704 tty_unlock(tp);
705
706 return error;
707 }
708
709 /*
710 * Line discipline callback
711 *
712 * Locks: tty_lock() is assumed held on entry and exit.
713 */
714 __private_extern__ int
715 ptsstop(struct tty* tp, int flush)
716 {
717 struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
718 int flag;
719
720 if (pti == NULL) {
721 return ENXIO;
722 }
723
724 /* note: FLUSHREAD and FLUSHWRITE already ok */
725 if (flush == 0) {
726 flush = TIOCPKT_STOP;
727 pti->pt_flags |= PF_STOPPED;
728 } else {
729 pti->pt_flags &= ~PF_STOPPED;
730 }
731 pti->pt_send |= flush;
732 /* change of perspective */
733 flag = 0;
734 if (flush & FREAD) {
735 flag |= FWRITE;
736 }
737 if (flush & FWRITE) {
738 flag |= FREAD;
739 }
740 ptcwakeup(tp, flag);
741 return 0;
742 }
743
744 __private_extern__ int
745 ptsreset(__unused int uban)
746 {
747 return 0;
748 }
749
750 int
751 ptsselect(dev_t dev, int rw, void *wql, proc_t p)
752 {
753 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
754 struct tty *tp;
755 int retval = 0;
756
757 if (pti == NULL) {
758 return ENXIO;
759 }
760 tp = pti->pt_tty;
761 if (tp == NULL) {
762 return ENXIO;
763 }
764
765 tty_lock(tp);
766
767 switch (rw) {
768 case FREAD:
769 if (ISSET(tp->t_state, TS_ZOMBIE)) {
770 retval = 1;
771 break;
772 }
773
774 retval = ttnread(tp);
775 if (retval > 0) {
776 break;
777 }
778
779 selrecord(p, &tp->t_rsel, wql);
780 break;
781 case FWRITE:
782 if (ISSET(tp->t_state, TS_ZOMBIE)) {
783 retval = 1;
784 break;
785 }
786
787 if ((tp->t_outq.c_cc <= tp->t_lowat) &&
788 ISSET(tp->t_state, TS_CONNECTED)) {
789 retval = tp->t_hiwat - tp->t_outq.c_cc;
790 break;
791 }
792
793 selrecord(p, &tp->t_wsel, wql);
794 break;
795 }
796
797 tty_unlock(tp);
798 return retval;
799 }
800
801 __private_extern__ int
802 ptcselect(dev_t dev, int rw, void *wql, proc_t p)
803 {
804 struct tty_dev_t *driver;
805 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
806 struct tty *tp;
807 int retval = 0;
808
809 if (pti == NULL) {
810 return ENXIO;
811 }
812 tp = pti->pt_tty;
813 tty_lock(tp);
814
815 if ((tp->t_state & TS_CONNECTED) == 0) {
816 retval = 1;
817 goto out;
818 }
819 switch (rw) {
820 case FREAD:
821 /*
822 * Need to block timeouts (ttrstart).
823 */
824 if ((tp->t_state & TS_ISOPEN) &&
825 tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) {
826 retval = (driver->fix_7828447) ? tp->t_outq.c_cc : 1;
827 break;
828 }
829 OS_FALLTHROUGH;
830
831 case 0: /* exceptional */
832 if ((tp->t_state & TS_ISOPEN) &&
833 (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
834 ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))) {
835 retval = 1;
836 break;
837 }
838 selrecord(p, &pti->pt_selr, wql);
839 break;
840
841
842 case FWRITE:
843 if (tp->t_state & TS_ISOPEN) {
844 retval = (TTYHOG - 2) - (tp->t_rawq.c_cc + tp->t_canq.c_cc);
845 if (retval > 0) {
846 retval = (driver->fix_7828447) ? retval : 1;
847 break;
848 }
849 if (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)) {
850 retval = 1;
851 break;
852 }
853 retval = 0;
854 }
855 selrecord(p, &pti->pt_selw, wql);
856 break;
857 }
858 out:
859 tty_unlock(tp);
860
861 return retval;
862 }
863
864 __private_extern__ int
865 ptcstop(__unused struct tty *tp, __unused int flush)
866 {
867 return 0;
868 }
869
870 __private_extern__ int
871 ptcreset(__unused int uban)
872 {
873 return 0;
874 }
875
876 __private_extern__ int
877 ptcwrite(dev_t dev, struct uio *uio, int flag)
878 {
879 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
880 struct tty *tp;
881 u_char *cp = NULL;
882 int cc = 0;
883 u_char locbuf[BUFSIZ];
884 int wcnt = 0;
885 int error = 0;
886
887 if (pti == NULL) {
888 return ENXIO;
889 }
890 tp = pti->pt_tty;
891 tty_lock(tp);
892
893 again:
894 if ((tp->t_state & TS_ISOPEN) == 0) {
895 goto block;
896 }
897 while (uio_resid(uio) > 0 || cc > 0) {
898 if (cc == 0) {
899 cc = MIN((int)uio_resid(uio), BUFSIZ);
900 cp = locbuf;
901 error = uiomove((caddr_t)cp, cc, uio);
902 if (error) {
903 goto out;
904 }
905 /* check again for safety */
906 if ((tp->t_state & TS_ISOPEN) == 0) {
907 /* adjust for data copied in but not written */
908 uio_setresid(uio, (uio_resid(uio) + cc));
909 error = EIO;
910 goto out;
911 }
912 }
913 while (cc > 0) {
914 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
915 (tp->t_canq.c_cc > 0 || !(tp->t_lflag & ICANON))) {
916 wakeup(TSA_HUP_OR_INPUT(tp));
917 goto block;
918 }
919 OS_ANALYZER_SUPPRESS("80961525") (*linesw[tp->t_line].l_rint)(*cp++, tp);
920 wcnt++;
921 cc--;
922 }
923 cc = 0;
924 }
925 out:
926 tty_unlock(tp);
927
928 return error;
929
930 block:
931 /*
932 * Come here to wait for replica to open, for space
933 * in outq, or space in rawq, or an empty canq.
934 */
935 if ((tp->t_state & TS_CONNECTED) == 0) {
936 /* adjust for data copied in but not written */
937 uio_setresid(uio, (uio_resid(uio) + cc));
938 error = EIO;
939 goto out;
940 }
941 if (flag & IO_NDELAY) {
942 /* adjust for data copied in but not written */
943 uio_setresid(uio, (uio_resid(uio) + cc));
944 if (wcnt == 0) {
945 error = EWOULDBLOCK;
946 }
947 goto out;
948 }
949 error = ttysleep(tp, TSA_PTC_WRITE(tp), TTOPRI | PCATCH, __FUNCTION__, 0);
950 if (error) {
951 /* adjust for data copied in but not written */
952 uio_setresid(uio, (uio_resid(uio) + cc));
953 goto out;
954 }
955 goto again;
956 }
957
958 /*
959 * ptyioctl: Assumes dev was opened and lock was initilized
960 */
961 __private_extern__ int
962 ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
963 {
964 struct tty_dev_t *driver;
965 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
966 struct tty *tp;
967 int stop, error = 0;
968 int allow_ext_ioctl = 1;
969
970 if (pti == NULL || pti->pt_tty == NULL) {
971 return ENXIO;
972 }
973
974 if (cmd == KMIOCDISABLCONS) {
975 return 0;
976 }
977
978 tp = pti->pt_tty;
979 tty_lock(tp);
980
981 u_char *cc = tp->t_cc;
982
983 /*
984 * Do not permit extended ioctls on the primary side of the pty unless
985 * the replica side has been successfully opened and initialized.
986 */
987 if (major(dev) == driver->primary &&
988 driver->fix_7070978 &&
989 ISSET(tp->t_state, TS_IOCTL_NOT_OK)) {
990 allow_ext_ioctl = 0;
991 }
992
993 /*
994 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
995 * ttywflush(tp) will hang if there are characters in the outq.
996 */
997 if (cmd == TIOCEXT && allow_ext_ioctl) {
998 /*
999 * When the EXTPROC bit is being toggled, we need
1000 * to send an TIOCPKT_IOCTL if the packet driver
1001 * is turned on.
1002 */
1003 if (*(int *)data) {
1004 if (pti->pt_flags & PF_PKT) {
1005 pti->pt_send |= TIOCPKT_IOCTL;
1006 ptcwakeup(tp, FREAD);
1007 }
1008 tp->t_lflag |= EXTPROC;
1009 } else {
1010 if ((tp->t_lflag & EXTPROC) &&
1011 (pti->pt_flags & PF_PKT)) {
1012 pti->pt_send |= TIOCPKT_IOCTL;
1013 ptcwakeup(tp, FREAD);
1014 }
1015 tp->t_lflag &= ~EXTPROC;
1016 }
1017 goto out;
1018 } else if (cdevsw[major(dev)].d_open == ptcopen) {
1019 switch (cmd) {
1020 case TIOCGPGRP:
1021 /*
1022 * We aviod calling ttioctl on the controller since,
1023 * in that case, tp must be the controlling terminal.
1024 */
1025 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
1026 goto out;
1027
1028 case TIOCPKT:
1029 if (*(int *)data) {
1030 if (pti->pt_flags & PF_UCNTL) {
1031 error = EINVAL;
1032 goto out;
1033 }
1034 pti->pt_flags |= PF_PKT;
1035 } else {
1036 pti->pt_flags &= ~PF_PKT;
1037 }
1038 goto out;
1039
1040 case TIOCUCNTL:
1041 if (*(int *)data) {
1042 if (pti->pt_flags & PF_PKT) {
1043 error = EINVAL;
1044 goto out;
1045 }
1046 pti->pt_flags |= PF_UCNTL;
1047 } else {
1048 pti->pt_flags &= ~PF_UCNTL;
1049 }
1050 goto out;
1051
1052 case TIOCSETP:
1053 case TIOCSETN:
1054 case TIOCSETD:
1055 case TIOCSETA_32:
1056 case TIOCSETAW_32:
1057 case TIOCSETAF_32:
1058 case TIOCSETA_64:
1059 case TIOCSETAW_64:
1060 case TIOCSETAF_64:
1061 ndflush(&tp->t_outq, tp->t_outq.c_cc);
1062 break;
1063
1064 case TIOCSIG:
1065 if (*(unsigned int *)data >= NSIG ||
1066 *(unsigned int *)data == 0) {
1067 error = EINVAL;
1068 goto out;
1069 }
1070 if ((tp->t_lflag & NOFLSH) == 0) {
1071 ttyflush(tp, FREAD | FWRITE);
1072 }
1073 if ((*(unsigned int *)data == SIGINFO) &&
1074 ((tp->t_lflag & NOKERNINFO) == 0)) {
1075 ttyinfo_locked(tp);
1076 }
1077 /*
1078 * SAFE: All callers drop the lock on return and
1079 * SAFE: the linesw[] will short circut this call
1080 * SAFE: if the ioctl() is eaten before the lower
1081 * SAFE: level code gets to see it.
1082 */
1083 tty_pgsignal_locked(tp, *(unsigned int *)data, 1);
1084 goto out;
1085
1086 case TIOCPTYGRANT: /* grantpt(3) */
1087 /*
1088 * Change the uid of the replica to that of the calling
1089 * thread, change the gid of the replica to GID_TTY,
1090 * change the mode to 0620 (rw--w----).
1091 */
1092 {
1093 error = _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY);
1094 if (major(dev) == driver->primary) {
1095 if (driver->mac_notify) {
1096 #if CONFIG_MACF
1097 if (!error) {
1098 tty_unlock(tp);
1099 mac_pty_notify_grant(p, tp, dev, NULL);
1100 tty_lock(tp);
1101 }
1102 #endif
1103 } else {
1104 error = 0;
1105 }
1106 }
1107 goto out;
1108 }
1109
1110 case TIOCPTYGNAME: /* ptsname(3) */
1111 /*
1112 * Report the name of the replica device in *data
1113 * (128 bytes max.). Use the same template string
1114 * used for calling devfs_make_node() to create it.
1115 */
1116 pty_get_name(dev, data, 128);
1117 error = 0;
1118 goto out;
1119
1120 case TIOCPTYUNLK: /* unlockpt(3) */
1121 /*
1122 * Unlock the replica device so that it can be opened.
1123 */
1124 if (major(dev) == driver->primary) {
1125 pti->pt_flags |= PF_UNLOCKED;
1126 }
1127 error = 0;
1128 goto out;
1129
1130 case FIONBIO: /* set/clear non-blocking i/o */
1131 case FIOASYNC:
1132 /*
1133 * These probably come from sys_fcntl_nocancel(). Nothing specific
1134 * to serial devices here, so they should be allowed even if the
1135 * replica is closed. The implementation in ttioctl_locked() is
1136 * safe to call in this case. Bypass the line discipline's l_ioctl
1137 * implementation in case it is not. In practice l_ioctl is
1138 * completely unused anyway (existing line disciplines set it to
1139 * l_noioctl, and the loadable line discipline mechanism is used
1140 * nowhere and not exposed to third parties).
1141 */
1142 error = ttioctl_locked(tp, cmd, data, flag, p);
1143 goto out;
1144 }
1145
1146 /*
1147 * Fail all other calls; pty primaries are not serial devices;
1148 * we only pretend they are when the replica side of the pty is
1149 * already open.
1150 */
1151 if (!allow_ext_ioctl) {
1152 error = ENOTTY;
1153 goto out;
1154 }
1155 }
1156 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1157 if (error == ENOTTY) {
1158 error = ttioctl_locked(tp, cmd, data, flag, p);
1159 if (error == ENOTTY) {
1160 if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) {
1161 /* Process the UIOCMD ioctl group */
1162 if (cmd & 0xff) {
1163 pti->pt_ucntl = (u_char)cmd;
1164 ptcwakeup(tp, FREAD);
1165 }
1166 error = 0;
1167 goto out;
1168 } else if (cmd == TIOCSBRK || cmd == TIOCCBRK) {
1169 /*
1170 * POSIX conformance; rdar://3936338
1171 *
1172 * Clear ENOTTY in the case of setting or
1173 * clearing a break failing because pty's
1174 * don't support break like real serial
1175 * ports.
1176 */
1177 error = 0;
1178 goto out;
1179 }
1180 }
1181 }
1182
1183 /*
1184 * If external processing and packet mode send ioctl packet.
1185 */
1186 if ((tp->t_lflag & EXTPROC) && (pti->pt_flags & PF_PKT)) {
1187 switch (cmd) {
1188 case TIOCSETA_32:
1189 case TIOCSETAW_32:
1190 case TIOCSETAF_32:
1191 case TIOCSETA_64:
1192 case TIOCSETAW_64:
1193 case TIOCSETAF_64:
1194 case TIOCSETP:
1195 case TIOCSETN:
1196 case TIOCSETC:
1197 case TIOCSLTC:
1198 case TIOCLBIS:
1199 case TIOCLBIC:
1200 case TIOCLSET:
1201 pti->pt_send |= TIOCPKT_IOCTL;
1202 ptcwakeup(tp, FREAD);
1203 break;
1204 default:
1205 break;
1206 }
1207 }
1208 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
1209 && CCEQ(cc[VSTART], CTRL('q'));
1210 if (pti->pt_flags & PF_NOSTOP) {
1211 if (stop) {
1212 pti->pt_send &= ~TIOCPKT_NOSTOP;
1213 pti->pt_send |= TIOCPKT_DOSTOP;
1214 pti->pt_flags &= ~PF_NOSTOP;
1215 ptcwakeup(tp, FREAD);
1216 }
1217 } else {
1218 if (!stop) {
1219 pti->pt_send &= ~TIOCPKT_DOSTOP;
1220 pti->pt_send |= TIOCPKT_NOSTOP;
1221 pti->pt_flags |= PF_NOSTOP;
1222 ptcwakeup(tp, FREAD);
1223 }
1224 }
1225 out:
1226 tty_unlock(tp);
1227
1228 return error;
1229 }
1230