]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/tty_dev.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / tty_dev.c
CommitLineData
fe8ab488 1/*
f427ee49 2 * Copyright (c) 1997-2020 Apple Inc. All rights reserved.
fe8ab488
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
fe8ab488
A
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.
0a7de745 14 *
fe8ab488
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
fe8ab488
A
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.
0a7de745 25 *
fe8ab488
A
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>
0a7de745
A
78#include <sys/vnode_internal.h> /* _devfs_setattr() */
79#include <sys/stat.h> /* _devfs_setattr() */
fe8ab488
A
80#include <sys/user.h>
81#include <sys/signalvar.h>
82#include <sys/sysctl.h>
83#include <miscfs/devfs/devfs.h>
0a7de745 84#include <miscfs/devfs/devfsdefs.h> /* DEVFS_LOCK()/DEVFS_UNLOCK() */
f427ee49 85#include <dev/kmreg_com.h>
fe8ab488
A
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 */
94static int _devfs_setattr(void *, unsigned short, uid_t, gid_t);
95
96/*
97 * Forward declarations
98 */
99static void ptcwakeup(struct tty *tp, int flag);
0a7de745
A
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;
fe8ab488
A
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 */
126static int
127_devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid)
128{
0a7de745
A
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;
fe8ab488
A
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);
0a7de745 165 if (error) {
fe8ab488 166 goto out;
0a7de745 167 }
fe8ab488
A
168 error = vnode_setattr(nd.ni_vp, &va, ctx);
169 vnode_put(nd.ni_vp);
170 nameidone(&nd);
171 goto out;
172 }
173
174out:
0a7de745 175 return error;
fe8ab488
A
176}
177
0a7de745 178#define BUFSIZ 100 /* Chunk size iomoved to/from user */
fe8ab488
A
179
180static struct tty_dev_t *tty_dev_head;
181
182__private_extern__ void
183tty_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 master
198 * PF_OPEN_S First open of slave
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
207static struct tty_dev_t *
208pty_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->master == major || driver->slave == major)) {
214 break;
215 }
216 }
217 return driver;
218}
219
220static struct ptmx_ioctl *
221pty_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 */
236static int
237pty_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
246static int
247pty_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
257ptsopen(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) {
0a7de745 273 termioschars(&tp->t_termios); /* Set up default chars */
fe8ab488
A
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;
0a7de745 279 ttsetwater(tp); /* would be done in xxparam() */
fe8ab488 280 } else if ((tp->t_state & TS_XCLUDE) && kauth_cred_issuser(kauth_cred_get())) {
0a7de745 281 error = EBUSY;
fe8ab488
A
282 goto out;
283 }
0a7de745 284 if (tp->t_oproc) { /* Ctrlr still around. */
fe8ab488 285 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
0a7de745 286 }
fe8ab488 287 while ((tp->t_state & TS_CARR_ON) == 0) {
0a7de745 288 if (flag & FNONBLOCK) {
fe8ab488 289 break;
0a7de745 290 }
fe8ab488 291 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, __FUNCTION__, 0);
0a7de745 292 if (error) {
fe8ab488 293 goto out;
0a7de745 294 }
fe8ab488
A
295 }
296 error = (*linesw[tp->t_line].l_open)(dev, tp);
297 /* Successful open; mark as open by the slave */
298
299 pti->pt_flags |= PF_OPEN_S;
300 CLR(tp->t_state, TS_IOCTL_NOT_OK);
0a7de745
A
301 if (error == 0) {
302 ptcwakeup(tp, FREAD | FWRITE);
303 }
fe8ab488
A
304
305out:
306 tty_unlock(tp);
0a7de745 307 return error;
fe8ab488
A
308}
309
310__private_extern__ int
311ptsclose(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 */
0a7de745
A
320#define FIX_VSX_HANG 1
321#ifdef FIX_VSX_HANG
fe8ab488
A
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;
a39ff7e2 327
0a7de745
A
328 if (pti == NULL) {
329 return ENXIO;
330 }
fe8ab488
A
331
332 tp = pti->pt_tty;
333 tty_lock(tp);
0a7de745 334#ifdef FIX_VSX_HANG
fe8ab488
A
335 save_timeout = tp->t_timeout;
336 tp->t_timeout = 60;
337#endif
a39ff7e2
A
338 /*
339 * Close the line discipline and backing TTY structures.
340 */
fe8ab488 341 err = (*linesw[tp->t_line].l_close)(tp, flag);
a39ff7e2
A
342 (void)ttyclose(tp);
343
344 /*
345 * Flush data and notify any waiters on the master side of this PTY.
346 */
347 ptsstop(tp, FREAD | FWRITE);
0a7de745 348#ifdef FIX_VSX_HANG
fe8ab488
A
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
0a7de745 359 return err;
fe8ab488
A
360}
361
362__private_extern__ int
363ptsread(dev_t dev, struct uio *uio, int flag)
364{
365 proc_t p = current_proc();
366 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
367 struct tty *tp;
368 int error = 0;
369 struct uthread *ut;
370 struct pgrp *pg;
371
0a7de745
A
372 if (pti == NULL) {
373 return ENXIO;
374 }
fe8ab488
A
375 tp = pti->pt_tty;
376 tty_lock(tp);
377
378 ut = (struct uthread *)get_bsdthread_info(current_thread());
379again:
380 if (pti->pt_flags & PF_REMOTE) {
381 while (isbackground(p, tp)) {
382 if ((p->p_sigignore & sigmask(SIGTTIN)) ||
383 (ut->uu_sigmask & sigmask(SIGTTIN)) ||
384 p->p_lflag & P_LPPWAIT) {
385 error = EIO;
386 goto out;
387 }
388
389
390 pg = proc_pgrp(p);
391 if (pg == PGRP_NULL) {
392 error = EIO;
393 goto out;
394 }
395 /*
396 * SAFE: We about to drop the lock ourselves by
397 * SAFE: erroring out or sleeping anyway.
398 */
399 tty_unlock(tp);
400 if (pg->pg_jobc == 0) {
401 pg_rele(pg);
402 tty_lock(tp);
403 error = EIO;
404 goto out;
405 }
406 pgsignal(pg, SIGTTIN, 1);
407 pg_rele(pg);
408 tty_lock(tp);
409
410 error = ttysleep(tp, &ptsread, TTIPRI | PCATCH | PTTYBLOCK, __FUNCTION__, hz);
0a7de745
A
411 if (error) {
412 goto out;
413 }
fe8ab488
A
414 }
415 if (tp->t_canq.c_cc == 0) {
416 if (flag & IO_NDELAY) {
417 error = EWOULDBLOCK;
418 goto out;
419 }
420 error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH, __FUNCTION__, 0);
0a7de745
A
421 if (error) {
422 goto out;
423 }
fe8ab488
A
424 goto again;
425 }
426 while (tp->t_canq.c_cc > 1 && uio_resid(uio) > 0) {
427 int cc;
428 char buf[BUFSIZ];
429
430 cc = MIN((int)uio_resid(uio), BUFSIZ);
431 // Don't copy the very last byte
432 cc = MIN(cc, tp->t_canq.c_cc - 1);
433 cc = q_to_b(&tp->t_canq, (u_char *)buf, cc);
434 error = uiomove(buf, cc, uio);
0a7de745 435 if (error) {
fe8ab488 436 break;
0a7de745 437 }
fe8ab488 438 }
0a7de745 439 if (tp->t_canq.c_cc == 1) {
fe8ab488 440 (void) getc(&tp->t_canq);
0a7de745
A
441 }
442 if (tp->t_canq.c_cc) {
443 goto out;
444 }
445 } else if (tp->t_oproc) {
446 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
447 }
fe8ab488
A
448 ptcwakeup(tp, FWRITE);
449out:
450 tty_unlock(tp);
0a7de745 451 return error;
fe8ab488
A
452}
453
454/*
455 * Write to pseudo-tty.
456 * Wakeups of controlling tty will happen
457 * indirectly, when tty driver calls ptsstart.
458 */
459__private_extern__ int
460ptswrite(dev_t dev, struct uio *uio, int flag)
461{
462 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
463 struct tty *tp;
464 int error;
465
0a7de745
A
466 if (pti == NULL) {
467 return ENXIO;
468 }
fe8ab488
A
469 tp = pti->pt_tty;
470 tty_lock(tp);
471
0a7de745 472 if (tp->t_oproc == 0) {
fe8ab488 473 error = EIO;
0a7de745
A
474 } else {
475 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
476 }
fe8ab488
A
477
478 tty_unlock(tp);
479
0a7de745 480 return error;
fe8ab488
A
481}
482
483/*
484 * Start output on pseudo-tty.
485 * Wake up process selecting or sleeping for input from controlling tty.
486 *
487 * t_oproc for this driver; called from within the line discipline
488 *
489 * Locks: Assumes tp is locked on entry, remains locked on exit
490 */
491static void
492ptsstart(struct tty *tp)
493{
494 struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
0a7de745 495 if (pti == NULL) {
fe8ab488 496 goto out;
0a7de745
A
497 }
498 if (tp->t_state & TS_TTSTOP) {
499 goto out;
500 }
fe8ab488
A
501 if (pti->pt_flags & PF_STOPPED) {
502 pti->pt_flags &= ~PF_STOPPED;
503 pti->pt_send = TIOCPKT_START;
504 }
505 ptcwakeup(tp, FREAD);
506out:
507 return;
508}
509
cb323159
A
510static void
511ptcwakeup_knote(struct selinfo *sip, long hint)
512{
513 if ((sip->si_flags & SI_KNPOSTING) == 0) {
514 sip->si_flags |= SI_KNPOSTING;
515 KNOTE(&sip->si_note, hint);
516 sip->si_flags &= ~SI_KNPOSTING;
517 }
518}
519
fe8ab488
A
520/*
521 * Locks: Assumes tty_lock() is held over this call.
522 */
523static void
524ptcwakeup(struct tty *tp, int flag)
525{
526 struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
0a7de745 527 if (pti == NULL) {
fe8ab488 528 return;
0a7de745 529 }
fe8ab488
A
530
531 if (flag & FREAD) {
532 selwakeup(&pti->pt_selr);
533 wakeup(TSA_PTC_READ(tp));
cb323159 534 ptcwakeup_knote(&pti->pt_selr, 1);
fe8ab488
A
535 }
536 if (flag & FWRITE) {
537 selwakeup(&pti->pt_selw);
538 wakeup(TSA_PTC_WRITE(tp));
cb323159 539 ptcwakeup_knote(&pti->pt_selw, 1);
fe8ab488
A
540 }
541}
542
543__private_extern__ int
544ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p)
545{
546 struct tty_dev_t *driver;
547 struct ptmx_ioctl *pti = pty_get_ioctl(dev, PF_OPEN_M, &driver);
548 if (pti == NULL) {
0a7de745 549 return ENXIO;
fe8ab488 550 } else if (pti == (struct ptmx_ioctl*)-1) {
0a7de745 551 return EREDRIVEOPEN;
fe8ab488
A
552 }
553
554 struct tty *tp = pti->pt_tty;
555 tty_lock(tp);
556
557 /* If master is open OR slave is still draining, pty is still busy */
558 if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) {
559 tty_unlock(tp);
560 /*
561 * If master is closed, we are the only reference, so we
562 * need to clear the master open bit
563 */
564 if (!tp->t_oproc) {
565 pty_free_ioctl(dev, PF_OPEN_M);
566 }
567 return EBUSY;
568 }
569 tp->t_oproc = ptsstart;
570 CLR(tp->t_state, TS_ZOMBIE);
571 SET(tp->t_state, TS_IOCTL_NOT_OK);
572#ifdef sun4c
573 tp->t_stop = ptsstop;
574#endif
575 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
576 tp->t_lflag &= ~EXTPROC;
577
578 if (driver->open_reset) {
579 pti->pt_flags = PF_UNLOCKED;
580 pti->pt_send = 0;
581 pti->pt_ucntl = 0;
582 }
583
584 tty_unlock(tp);
585 return 0;
586}
587
588__private_extern__ int
589ptcclose(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p)
590{
591 struct tty_dev_t *driver;
592 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
593 struct tty *tp;
a39ff7e2
A
594 struct knote *kn;
595
596 if (!pti) {
597 return ENXIO;
598 }
fe8ab488 599
fe8ab488
A
600 tp = pti->pt_tty;
601 tty_lock(tp);
602
fe8ab488 603 /*
a39ff7e2
A
604 * XXX MDMBUF makes no sense for PTYs, but would inhibit an `l_modem`.
605 * CLOCAL makes sense but isn't supported. Special `l_modem`s that ignore
606 * carrier drop make no sense for PTYs but may be in use because other parts
607 * of the line discipline make sense for PTYs. Recover by doing everything
608 * that a normal `ttymodem` would have done except for sending SIGHUP.
fe8ab488 609 */
a39ff7e2 610 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
fe8ab488
A
611 if (tp->t_state & TS_ISOPEN) {
612 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
613 tp->t_state |= TS_ZOMBIE;
614 ttyflush(tp, FREAD | FWRITE);
615 }
616
a39ff7e2
A
617 /*
618 * Null out the backing TTY struct's open procedure to prevent starting
619 * slaves through `ptsstart`.
620 */
621 tp->t_oproc = NULL;
622
623 /*
624 * Clear any select or kevent waiters under the lock.
625 */
626 SLIST_FOREACH(kn, &pti->pt_selr.si_note, kn_selnext) {
627 KNOTE_DETACH(&pti->pt_selr.si_note, kn);
628 }
629 selthreadclear(&pti->pt_selr);
630 SLIST_FOREACH(kn, &pti->pt_selw.si_note, kn_selnext) {
631 KNOTE_DETACH(&pti->pt_selw.si_note, kn);
632 }
633 selthreadclear(&pti->pt_selw);
fe8ab488
A
634
635 tty_unlock(tp);
636
637 pty_free_ioctl(dev, PF_OPEN_M);
638#if CONFIG_MACF
639 if (driver->mac_notify) {
640 mac_pty_notify_close(p, tp, dev, NULL);
641 }
642#endif
643
0a7de745 644 return 0;
fe8ab488
A
645}
646
647__private_extern__ int
648ptcread(dev_t dev, struct uio *uio, int flag)
649{
650 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
651 struct tty *tp;
652 char buf[BUFSIZ];
653 int error = 0, cc;
654
0a7de745
A
655 if (pti == NULL) {
656 return ENXIO;
657 }
fe8ab488
A
658 tp = pti->pt_tty;
659 tty_lock(tp);
660
661 /*
662 * We want to block until the slave
663 * is open, and there's something to read;
664 * but if we lost the slave or we're NBIO,
665 * then return the appropriate error instead.
666 */
667 for (;;) {
668 if (tp->t_state & TS_ISOPEN) {
669 if (pti->pt_flags & PF_PKT && pti->pt_send) {
670 error = ureadc((int)pti->pt_send, uio);
0a7de745 671 if (error) {
fe8ab488 672 goto out;
0a7de745 673 }
fe8ab488 674 if (pti->pt_send & TIOCPKT_IOCTL) {
f427ee49
A
675#ifdef __LP64__
676 if (uio->uio_segflg == UIO_USERSPACE32) {
677 static struct termios32 tio32;
678 cc = MIN((int)uio_resid(uio), (int)sizeof(tio32));
679 termios64to32((struct user_termios *)&tp->t_termios,
680 (struct termios32 *)&tio32);
681 uiomove((caddr_t)&tio32, cc, uio);
682#else
683 if (uio->uio_segflg == UIO_USERSPACE64) {
684 static struct user_termios tio64;
685 cc = MIN((int)uio_resid(uio), (int)sizeof(tio64));
686 termios32to64((struct termios32 *)&tp->t_termios,
687 (struct user_termios *)&tio64);
688 uiomove((caddr_t)&tio64, cc, uio);
689#endif
690 } else {
691 cc = MIN((int)uio_resid(uio), (int)sizeof(tp->t_termios));
692 uiomove((caddr_t)&tp->t_termios, cc, uio);
693 }
fe8ab488
A
694 }
695 pti->pt_send = 0;
696 goto out;
697 }
698 if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
699 error = ureadc((int)pti->pt_ucntl, uio);
0a7de745 700 if (error) {
fe8ab488 701 goto out;
0a7de745 702 }
fe8ab488
A
703 pti->pt_ucntl = 0;
704 goto out;
705 }
0a7de745 706 if (tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) {
fe8ab488 707 break;
0a7de745
A
708 }
709 }
710 if ((tp->t_state & TS_CONNECTED) == 0) {
711 goto out; /* EOF */
fe8ab488 712 }
fe8ab488
A
713 if (flag & IO_NDELAY) {
714 error = EWOULDBLOCK;
715 goto out;
716 }
717 error = ttysleep(tp, TSA_PTC_READ(tp), TTIPRI | PCATCH, __FUNCTION__, 0);
0a7de745
A
718 if (error) {
719 goto out;
720 }
fe8ab488 721 }
0a7de745 722 if (pti->pt_flags & (PF_PKT | PF_UCNTL)) {
fe8ab488 723 error = ureadc(0, uio);
0a7de745 724 }
fe8ab488
A
725 while (uio_resid(uio) > 0 && error == 0) {
726 cc = q_to_b(&tp->t_outq, (u_char *)buf, MIN((int)uio_resid(uio), BUFSIZ));
0a7de745 727 if (cc <= 0) {
fe8ab488 728 break;
0a7de745 729 }
fe8ab488
A
730 error = uiomove(buf, cc, uio);
731 }
732 (*linesw[tp->t_line].l_start)(tp);
733
734out:
735 tty_unlock(tp);
736
0a7de745 737 return error;
fe8ab488
A
738}
739
740/*
741 * Line discipline callback
742 *
743 * Locks: tty_lock() is assumed held on entry and exit.
744 */
745__private_extern__ int
746ptsstop(struct tty* tp, int flush)
747{
748 struct ptmx_ioctl *pti = pty_get_ioctl(tp->t_dev, 0, NULL);
749 int flag;
750
0a7de745
A
751 if (pti == NULL) {
752 return ENXIO;
753 }
fe8ab488
A
754
755 /* note: FLUSHREAD and FLUSHWRITE already ok */
756 if (flush == 0) {
757 flush = TIOCPKT_STOP;
758 pti->pt_flags |= PF_STOPPED;
0a7de745 759 } else {
fe8ab488 760 pti->pt_flags &= ~PF_STOPPED;
0a7de745 761 }
fe8ab488
A
762 pti->pt_send |= flush;
763 /* change of perspective */
764 flag = 0;
0a7de745 765 if (flush & FREAD) {
fe8ab488 766 flag |= FWRITE;
0a7de745
A
767 }
768 if (flush & FWRITE) {
fe8ab488 769 flag |= FREAD;
0a7de745 770 }
fe8ab488
A
771 ptcwakeup(tp, flag);
772 return 0;
773}
774
775__private_extern__ int
776ptsreset(__unused int uban)
777{
0a7de745 778 return 0;
fe8ab488
A
779}
780
781int
782ptsselect(dev_t dev, int rw, void *wql, proc_t p)
783{
784 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
785 struct tty *tp;
786 int retval = 0;
787
0a7de745
A
788 if (pti == NULL) {
789 return ENXIO;
790 }
fe8ab488 791 tp = pti->pt_tty;
0a7de745
A
792 if (tp == NULL) {
793 return ENXIO;
794 }
fe8ab488
A
795
796 tty_lock(tp);
797
798 switch (rw) {
799 case FREAD:
800 if (ISSET(tp->t_state, TS_ZOMBIE)) {
801 retval = 1;
802 break;
803 }
804
805 retval = ttnread(tp);
806 if (retval > 0) {
807 break;
808 }
809
810 selrecord(p, &tp->t_rsel, wql);
811 break;
812 case FWRITE:
813 if (ISSET(tp->t_state, TS_ZOMBIE)) {
814 retval = 1;
815 break;
816 }
817
818 if ((tp->t_outq.c_cc <= tp->t_lowat) &&
0a7de745 819 ISSET(tp->t_state, TS_CONNECTED)) {
fe8ab488
A
820 retval = tp->t_hiwat - tp->t_outq.c_cc;
821 break;
822 }
823
824 selrecord(p, &tp->t_wsel, wql);
825 break;
826 }
827
828 tty_unlock(tp);
0a7de745 829 return retval;
fe8ab488
A
830}
831
832__private_extern__ int
833ptcselect(dev_t dev, int rw, void *wql, proc_t p)
834{
835 struct tty_dev_t *driver;
836 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
837 struct tty *tp;
838 int retval = 0;
839
0a7de745
A
840 if (pti == NULL) {
841 return ENXIO;
842 }
fe8ab488
A
843 tp = pti->pt_tty;
844 tty_lock(tp);
845
846 if ((tp->t_state & TS_CONNECTED) == 0) {
847 retval = 1;
848 goto out;
849 }
850 switch (rw) {
fe8ab488
A
851 case FREAD:
852 /*
853 * Need to block timeouts (ttrstart).
854 */
0a7de745
A
855 if ((tp->t_state & TS_ISOPEN) &&
856 tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) {
fe8ab488
A
857 retval = (driver->fix_7828447) ? tp->t_outq.c_cc : 1;
858 break;
859 }
f427ee49 860 OS_FALLTHROUGH;
fe8ab488 861
5c9f4661 862 case 0: /* exceptional */
0a7de745
A
863 if ((tp->t_state & TS_ISOPEN) &&
864 (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
865 ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))) {
fe8ab488
A
866 retval = 1;
867 break;
868 }
869 selrecord(p, &pti->pt_selr, wql);
870 break;
871
872
873 case FWRITE:
0a7de745 874 if (tp->t_state & TS_ISOPEN) {
fe8ab488 875 if (pti->pt_flags & PF_REMOTE) {
5c9f4661
A
876 if (tp->t_canq.c_cc == 0) {
877 retval = (driver->fix_7828447) ? (TTYHOG - 1) : 1;
878 break;
0a7de745 879 }
fe8ab488 880 } else {
5c9f4661
A
881 retval = (TTYHOG - 2) - (tp->t_rawq.c_cc + tp->t_canq.c_cc);
882 if (retval > 0) {
883 retval = (driver->fix_7828447) ? retval : 1;
884 break;
885 }
0a7de745 886 if (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)) {
5c9f4661
A
887 retval = 1;
888 break;
889 }
890 retval = 0;
fe8ab488
A
891 }
892 }
893 selrecord(p, &pti->pt_selw, wql);
894 break;
fe8ab488
A
895 }
896out:
897 tty_unlock(tp);
898
0a7de745 899 return retval;
fe8ab488
A
900}
901
902__private_extern__ int
903ptcstop(__unused struct tty *tp, __unused int flush)
904{
0a7de745 905 return 0;
fe8ab488
A
906}
907
908__private_extern__ int
909ptcreset(__unused int uban)
910{
0a7de745 911 return 0;
fe8ab488
A
912}
913
914__private_extern__ int
915ptcwrite(dev_t dev, struct uio *uio, int flag)
916{
917 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, NULL);
918 struct tty *tp;
919 u_char *cp = NULL;
920 int cc = 0;
921 u_char locbuf[BUFSIZ];
922 int wcnt = 0;
923 int error = 0;
924
0a7de745
A
925 if (pti == NULL) {
926 return ENXIO;
927 }
fe8ab488
A
928 tp = pti->pt_tty;
929 tty_lock(tp);
930
931again:
0a7de745 932 if ((tp->t_state & TS_ISOPEN) == 0) {
fe8ab488 933 goto block;
0a7de745 934 }
fe8ab488 935 if (pti->pt_flags & PF_REMOTE) {
0a7de745 936 if (tp->t_canq.c_cc) {
fe8ab488 937 goto block;
0a7de745 938 }
fe8ab488 939 while ((uio_resid(uio) > 0 || cc > 0) &&
0a7de745 940 tp->t_canq.c_cc < TTYHOG - 1) {
fe8ab488
A
941 if (cc == 0) {
942 cc = MIN((int)uio_resid(uio), BUFSIZ);
943 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
944 cp = locbuf;
945 error = uiomove((caddr_t)cp, cc, uio);
0a7de745 946 if (error) {
fe8ab488 947 goto out;
0a7de745 948 }
fe8ab488
A
949 /* check again for safety */
950 if ((tp->t_state & TS_ISOPEN) == 0) {
951 /* adjust as usual */
952 uio_setresid(uio, (uio_resid(uio) + cc));
953 error = EIO;
954 goto out;
955 }
956 }
957 if (cc > 0) {
958 cc = b_to_q((u_char *)cp, cc, &tp->t_canq);
959 /*
960 * XXX we don't guarantee that the canq size
961 * is >= TTYHOG, so the above b_to_q() may
962 * leave some bytes uncopied. However, space
963 * is guaranteed for the null terminator if
964 * we don't fail here since (TTYHOG - 1) is
965 * not a multiple of CBSIZE.
966 */
0a7de745 967 if (cc > 0) {
fe8ab488 968 break;
0a7de745 969 }
fe8ab488
A
970 }
971 }
972 /* adjust for data copied in but not written */
973 uio_setresid(uio, (uio_resid(uio) + cc));
974 (void) putc(0, &tp->t_canq);
975 ttwakeup(tp);
976 wakeup(TSA_PTS_READ(tp));
977 goto out;
978 }
979 while (uio_resid(uio) > 0 || cc > 0) {
980 if (cc == 0) {
981 cc = MIN((int)uio_resid(uio), BUFSIZ);
982 cp = locbuf;
983 error = uiomove((caddr_t)cp, cc, uio);
0a7de745 984 if (error) {
fe8ab488 985 goto out;
0a7de745 986 }
fe8ab488
A
987 /* check again for safety */
988 if ((tp->t_state & TS_ISOPEN) == 0) {
989 /* adjust for data copied in but not written */
990 uio_setresid(uio, (uio_resid(uio) + cc));
991 error = EIO;
992 goto out;
993 }
994 }
995 while (cc > 0) {
996 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
0a7de745 997 (tp->t_canq.c_cc > 0 || !(tp->t_lflag & ICANON))) {
fe8ab488
A
998 wakeup(TSA_HUP_OR_INPUT(tp));
999 goto block;
1000 }
1001 (*linesw[tp->t_line].l_rint)(*cp++, tp);
1002 wcnt++;
1003 cc--;
1004 }
1005 cc = 0;
1006 }
1007out:
1008 tty_unlock(tp);
1009
0a7de745 1010 return error;
fe8ab488
A
1011
1012block:
1013 /*
1014 * Come here to wait for slave to open, for space
1015 * in outq, or space in rawq, or an empty canq.
1016 */
1017 if ((tp->t_state & TS_CONNECTED) == 0) {
1018 /* adjust for data copied in but not written */
1019 uio_setresid(uio, (uio_resid(uio) + cc));
1020 error = EIO;
1021 goto out;
1022 }
1023 if (flag & IO_NDELAY) {
1024 /* adjust for data copied in but not written */
1025 uio_setresid(uio, (uio_resid(uio) + cc));
0a7de745 1026 if (wcnt == 0) {
fe8ab488 1027 error = EWOULDBLOCK;
0a7de745 1028 }
fe8ab488
A
1029 goto out;
1030 }
1031 error = ttysleep(tp, TSA_PTC_WRITE(tp), TTOPRI | PCATCH, __FUNCTION__, 0);
1032 if (error) {
1033 /* adjust for data copied in but not written */
1034 uio_setresid(uio, (uio_resid(uio) + cc));
1035 goto out;
1036 }
1037 goto again;
1038}
1039
cb323159
A
1040/*
1041 * ptyioctl: Assumes dev was opened and lock was initilized
1042 */
fe8ab488
A
1043__private_extern__ int
1044ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1045{
1046 struct tty_dev_t *driver;
1047 struct ptmx_ioctl *pti = pty_get_ioctl(dev, 0, &driver);
1048 struct tty *tp;
1049 int stop, error = 0;
1050 int allow_ext_ioctl = 1;
1051
cb323159 1052 if (pti == NULL || pti->pt_tty == NULL) {
0a7de745
A
1053 return ENXIO;
1054 }
cb323159 1055
f427ee49
A
1056 if (cmd == KMIOCDISABLCONS) {
1057 return 0;
1058 }
1059
fe8ab488
A
1060 tp = pti->pt_tty;
1061 tty_lock(tp);
1062
1063 u_char *cc = tp->t_cc;
1064
1065 /*
1066 * Do not permit extended ioctls on the master side of the pty unless
1067 * the slave side has been successfully opened and initialized.
1068 */
1069 if (major(dev) == driver->master &&
1070 driver->fix_7070978 &&
1071 ISSET(tp->t_state, TS_IOCTL_NOT_OK)) {
1072 allow_ext_ioctl = 0;
1073 }
1074
1075 /*
1076 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
1077 * ttywflush(tp) will hang if there are characters in the outq.
1078 */
1079 if (cmd == TIOCEXT && allow_ext_ioctl) {
1080 /*
1081 * When the EXTPROC bit is being toggled, we need
1082 * to send an TIOCPKT_IOCTL if the packet driver
1083 * is turned on.
1084 */
1085 if (*(int *)data) {
1086 if (pti->pt_flags & PF_PKT) {
1087 pti->pt_send |= TIOCPKT_IOCTL;
1088 ptcwakeup(tp, FREAD);
1089 }
1090 tp->t_lflag |= EXTPROC;
1091 } else {
1092 if ((tp->t_lflag & EXTPROC) &&
1093 (pti->pt_flags & PF_PKT)) {
1094 pti->pt_send |= TIOCPKT_IOCTL;
1095 ptcwakeup(tp, FREAD);
1096 }
1097 tp->t_lflag &= ~EXTPROC;
1098 }
1099 goto out;
0a7de745 1100 } else if (cdevsw[major(dev)].d_open == ptcopen) {
fe8ab488 1101 switch (cmd) {
fe8ab488
A
1102 case TIOCGPGRP:
1103 /*
1104 * We aviod calling ttioctl on the controller since,
1105 * in that case, tp must be the controlling terminal.
1106 */
1107 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
1108 goto out;
1109
1110 case TIOCPKT:
1111 if (*(int *)data) {
0a7de745 1112 if (pti->pt_flags & PF_UCNTL) {
fe8ab488
A
1113 error = EINVAL;
1114 goto out;
1115 }
1116 pti->pt_flags |= PF_PKT;
0a7de745 1117 } else {
fe8ab488 1118 pti->pt_flags &= ~PF_PKT;
0a7de745 1119 }
fe8ab488
A
1120 goto out;
1121
1122 case TIOCUCNTL:
1123 if (*(int *)data) {
0a7de745 1124 if (pti->pt_flags & PF_PKT) {
fe8ab488
A
1125 error = EINVAL;
1126 goto out;
1127 }
1128 pti->pt_flags |= PF_UCNTL;
0a7de745 1129 } else {
fe8ab488 1130 pti->pt_flags &= ~PF_UCNTL;
0a7de745 1131 }
fe8ab488
A
1132 goto out;
1133
1134 case TIOCREMOTE:
0a7de745 1135 if (*(int *)data) {
fe8ab488 1136 pti->pt_flags |= PF_REMOTE;
0a7de745 1137 } else {
fe8ab488 1138 pti->pt_flags &= ~PF_REMOTE;
0a7de745
A
1139 }
1140 ttyflush(tp, FREAD | FWRITE);
fe8ab488
A
1141 goto out;
1142
1143 case TIOCSETP:
1144 case TIOCSETN:
1145 case TIOCSETD:
1146 case TIOCSETA_32:
1147 case TIOCSETAW_32:
1148 case TIOCSETAF_32:
1149 case TIOCSETA_64:
1150 case TIOCSETAW_64:
1151 case TIOCSETAF_64:
1152 ndflush(&tp->t_outq, tp->t_outq.c_cc);
1153 break;
1154
1155 case TIOCSIG:
1156 if (*(unsigned int *)data >= NSIG ||
1157 *(unsigned int *)data == 0) {
1158 error = EINVAL;
1159 goto out;
1160 }
0a7de745
A
1161 if ((tp->t_lflag & NOFLSH) == 0) {
1162 ttyflush(tp, FREAD | FWRITE);
1163 }
fe8ab488 1164 if ((*(unsigned int *)data == SIGINFO) &&
0a7de745 1165 ((tp->t_lflag & NOKERNINFO) == 0)) {
fe8ab488 1166 ttyinfo_locked(tp);
0a7de745 1167 }
fe8ab488
A
1168 /*
1169 * SAFE: All callers drop the lock on return and
1170 * SAFE: the linesw[] will short circut this call
1171 * SAFE: if the ioctl() is eaten before the lower
1172 * SAFE: level code gets to see it.
1173 */
1174 tty_unlock(tp);
1175 tty_pgsignal(tp, *(unsigned int *)data, 1);
1176 tty_lock(tp);
1177 goto out;
1178
0a7de745 1179 case TIOCPTYGRANT: /* grantpt(3) */
fe8ab488
A
1180 /*
1181 * Change the uid of the slave to that of the calling
1182 * thread, change the gid of the slave to GID_TTY,
1183 * change the mode to 0620 (rw--w----).
1184 */
0a7de745
A
1185 {
1186 error = _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY);
1187 if (major(dev) == driver->master) {
1188 if (driver->mac_notify) {
fe8ab488 1189#if CONFIG_MACF
0a7de745
A
1190 if (!error) {
1191 tty_unlock(tp);
1192 mac_pty_notify_grant(p, tp, dev, NULL);
1193 tty_lock(tp);
fe8ab488 1194 }
0a7de745
A
1195#endif
1196 } else {
1197 error = 0;
fe8ab488 1198 }
fe8ab488 1199 }
0a7de745
A
1200 goto out;
1201 }
fe8ab488 1202
0a7de745 1203 case TIOCPTYGNAME: /* ptsname(3) */
fe8ab488
A
1204 /*
1205 * Report the name of the slave device in *data
1206 * (128 bytes max.). Use the same template string
1207 * used for calling devfs_make_node() to create it.
1208 */
1209 pty_get_name(dev, data, 128);
1210 error = 0;
1211 goto out;
0a7de745
A
1212
1213 case TIOCPTYUNLK: /* unlockpt(3) */
fe8ab488
A
1214 /*
1215 * Unlock the slave device so that it can be opened.
1216 */
1217 if (major(dev) == driver->master) {
1218 pti->pt_flags |= PF_UNLOCKED;
1219 }
1220 error = 0;
1221 goto out;
1222 }
1223
1224 /*
1225 * Fail all other calls; pty masters are not serial devices;
1226 * we only pretend they are when the slave side of the pty is
1227 * already open.
1228 */
1229 if (!allow_ext_ioctl) {
1230 error = ENOTTY;
1231 goto out;
1232 }
1233 }
1234 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1235 if (error == ENOTTY) {
1236 error = ttioctl_locked(tp, cmd, data, flag, p);
1237 if (error == ENOTTY) {
1238 if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) {
1239 /* Process the UIOCMD ioctl group */
1240 if (cmd & 0xff) {
1241 pti->pt_ucntl = (u_char)cmd;
1242 ptcwakeup(tp, FREAD);
1243 }
1244 error = 0;
1245 goto out;
1246 } else if (cmd == TIOCSBRK || cmd == TIOCCBRK) {
1247 /*
1248 * POSIX conformance; rdar://3936338
1249 *
1250 * Clear ENOTTY in the case of setting or
1251 * clearing a break failing because pty's
1252 * don't support break like real serial
1253 * ports.
1254 */
1255 error = 0;
1256 goto out;
1257 }
1258 }
1259 }
1260
1261 /*
1262 * If external processing and packet mode send ioctl packet.
1263 */
0a7de745
A
1264 if ((tp->t_lflag & EXTPROC) && (pti->pt_flags & PF_PKT)) {
1265 switch (cmd) {
fe8ab488
A
1266 case TIOCSETA_32:
1267 case TIOCSETAW_32:
1268 case TIOCSETAF_32:
1269 case TIOCSETA_64:
1270 case TIOCSETAW_64:
1271 case TIOCSETAF_64:
1272 case TIOCSETP:
1273 case TIOCSETN:
1274 case TIOCSETC:
1275 case TIOCSLTC:
1276 case TIOCLBIS:
1277 case TIOCLBIC:
1278 case TIOCLSET:
1279 pti->pt_send |= TIOCPKT_IOCTL;
1280 ptcwakeup(tp, FREAD);
f427ee49 1281 break;
fe8ab488
A
1282 default:
1283 break;
1284 }
1285 }
1286 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
0a7de745 1287 && CCEQ(cc[VSTART], CTRL('q'));
fe8ab488
A
1288 if (pti->pt_flags & PF_NOSTOP) {
1289 if (stop) {
1290 pti->pt_send &= ~TIOCPKT_NOSTOP;
1291 pti->pt_send |= TIOCPKT_DOSTOP;
1292 pti->pt_flags &= ~PF_NOSTOP;
1293 ptcwakeup(tp, FREAD);
1294 }
1295 } else {
1296 if (!stop) {
1297 pti->pt_send &= ~TIOCPKT_DOSTOP;
1298 pti->pt_send |= TIOCPKT_NOSTOP;
1299 pti->pt_flags |= PF_NOSTOP;
1300 ptcwakeup(tp, FREAD);
1301 }
1302 }
1303out:
1304 tty_unlock(tp);
1305
0a7de745 1306 return error;
fe8ab488 1307}