]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/tty_ptmx.c
xnu-1228.5.20.tar.gz
[apple/xnu.git] / bsd / kern / tty_ptmx.c
CommitLineData
2d21ac55
A
1/*
2 * Copyright (c) 1997-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1982, 1986, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
61 */
62
63/*
64 * Pseudo-teletype Driver
65 * (Actually two drivers, requiring two entries in 'cdevsw')
66 */
67#include "pty.h" /* XXX */
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/ioctl.h>
72#include <sys/proc_internal.h>
73#include <sys/kauth.h>
74#include <sys/tty.h>
75#include <sys/conf.h>
76#include <sys/file_internal.h>
77#include <sys/uio.h>
78#include <sys/kernel.h>
79#include <sys/vnode.h>
80#include <sys/vnode_internal.h> /* _devfs_setattr() */
81#include <sys/stat.h> /* _devfs_setattr() */
82#include <sys/user.h>
83#include <sys/signalvar.h>
84#include <sys/sysctl.h>
85#include <miscfs/devfs/devfs.h>
86#include <miscfs/devfs/devfsdefs.h> /* DEVFS_LOCK()/DEVFS_UNLOCK() */
87
88/* XXX belongs in devfs somewhere - LATER */
89int _devfs_setattr(void *, unsigned short, uid_t, gid_t);
90
91
92#define FREE_BSDSTATIC __private_extern__
93#define d_devtotty_t struct tty **
94
95/*
96 * Forward declarations
97 */
98int ptmx_init(int n_ptys);
99static void ptsd_start(struct tty *tp);
100static void ptmx_wakeup(struct tty *tp, int flag);
101FREE_BSDSTATIC d_open_t ptsd_open;
102FREE_BSDSTATIC d_close_t ptsd_close;
103FREE_BSDSTATIC d_read_t ptsd_read;
104FREE_BSDSTATIC d_write_t ptsd_write;
105FREE_BSDSTATIC d_ioctl_t cptyioctl; /* common ioctl */
106FREE_BSDSTATIC d_stop_t ptsd_stop;
107FREE_BSDSTATIC d_reset_t ptsd_reset;
108FREE_BSDSTATIC d_devtotty_t ptydevtotty;
109FREE_BSDSTATIC d_open_t ptmx_open;
110FREE_BSDSTATIC d_close_t ptmx_close;
111FREE_BSDSTATIC d_read_t ptmx_read;
112FREE_BSDSTATIC d_write_t ptmx_write;
113FREE_BSDSTATIC d_stop_t ptmx_stop; /* NO-OP */
114FREE_BSDSTATIC d_reset_t ptmx_reset;
115FREE_BSDSTATIC d_select_t ptmx_select;
116FREE_BSDSTATIC d_select_t ptsd_select;
117
118static int ptmx_major; /* dynamically assigned major number */
119static struct cdevsw ptmx_cdev = {
120 ptmx_open, ptmx_close, ptmx_read, ptmx_write,
121 cptyioctl, ptmx_stop, ptmx_reset, 0,
122 ptmx_select, eno_mmap, eno_strat, eno_getc,
123 eno_putc, D_TTY
124};
125
126static int ptsd_major; /* dynamically assigned major number */
127static struct cdevsw ptsd_cdev = {
128 ptsd_open, ptsd_close, ptsd_read, ptsd_write,
129 cptyioctl, ptsd_stop, ptsd_reset, 0,
130 ptsd_select, eno_mmap, eno_strat, eno_getc,
131 eno_putc, D_TTY
132};
133
134/*
135 * XXX Should be devfs function... and use VATTR mechanisms, per
136 * XXX vnode_setattr2(); only we maybe can't really get back to the
137 * XXX vnode here for cloning devices (but it works for *cloned* devices
138 * XXX that are not themselves cloning).
139 *
140 * Returns: 0 Success
141 * namei:???
142 * vnode_setattr:???
143 */
144int
145_devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid)
146{
147 devdirent_t *direntp = (devdirent_t *)handle;
148 devnode_t *devnodep;
149 int error = EACCES;
150 vfs_context_t ctx = vfs_context_current();;
151 struct vnode_attr va;
152
153 VATTR_INIT(&va);
154 VATTR_SET(&va, va_uid, uid);
155 VATTR_SET(&va, va_gid, gid);
156 VATTR_SET(&va, va_mode, mode & ALLPERMS);
157
158 /*
159 * If the TIOCPTYGRANT loses the race with the clone operation because
160 * this function is not part of devfs, and therefore can't take the
161 * devfs lock to protect the direntp update, then force user space to
162 * redrive the grant request.
163 */
164 if (direntp == NULL || (devnodep = direntp->de_dnp) == NULL) {
165 error = ERESTART;
166 goto out;
167 }
168
169 /*
170 * Only do this if we are operating on device that doesn't clone
171 * each time it's referenced. We perform a lookup on the device
172 * to insure we get the right instance. We can't just use the call
173 * to devfs_dntovn() to get the vp for the operation, because
174 * dn_dvm may not have been initialized.
175 */
176 if (devnodep->dn_clone == NULL) {
177 struct nameidata nd;
178 char name[128];
179
180 snprintf(name, sizeof(name), "/dev/%s", direntp->de_name);
181 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(name), ctx);
182 error = namei(&nd);
183 if (error)
184 goto out;
185 error = vnode_setattr(nd.ni_vp, &va, ctx);
186 vnode_put(nd.ni_vp);
187 nameidone(&nd);
188 goto out;
189 }
190
191out:
192 return(error);
193}
194
195
196
197#define BUFSIZ 100 /* Chunk size iomoved to/from user */
198
199/*
200 * ptmx == /dev/ptmx
201 * ptsd == /dev/pts[0123456789]{3}
202 */
203#define PTMX_TEMPLATE "ptmx"
204#define PTSD_TEMPLATE "ttys%03d"
205
206/*
207 * System-wide limit on the max number of cloned ptys
208 */
209#define PTMX_MAX_DEFAULT 127 /* 128 entries */
210#define PTMX_MAX_HARD 999 /* 1000 entries, due to PTSD_TEMPLATE */
211
212static int ptmx_max = PTMX_MAX_DEFAULT; /* default # of clones we allow */
213
214/* Range enforcement for the sysctl */
215static int
216sysctl_ptmx_max(__unused struct sysctl_oid *oidp, __unused void *arg1,
217 __unused int arg2, struct sysctl_req *req)
218{
219 int new_value, changed;
220 int error = sysctl_io_number(req, ptmx_max, sizeof(int), &new_value, &changed);
221 if (changed) {
222 if (new_value > 0 && new_value <= PTMX_MAX_HARD)
223 ptmx_max = new_value;
224 else
225 error = EINVAL;
226 }
227 return(error);
228}
229
230SYSCTL_NODE(_kern, KERN_TTY, tty, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "TTY");
231SYSCTL_PROC(_kern_tty, OID_AUTO, ptmx_max,
232 CTLTYPE_INT | CTLFLAG_RW,
233 &ptmx_max, 0, &sysctl_ptmx_max, "I", "ptmx_max");
234
235
236/*
237 * ptmx_ioctl is a pointer to a list of pointers to tty structures which is
238 * grown, as necessary, copied, and replaced, but never shrunk. The ioctl
239 * structures themselves pointed to from this list come and go as needed.
240 */
241struct ptmx_ioctl {
242 struct tty *pt_tty; /* pointer to ttymalloc()'ed data */
243 int pt_flags;
244 struct selinfo pt_selr;
245 struct selinfo pt_selw;
246 u_char pt_send;
247 u_char pt_ucntl;
248 void *pt_devhandle; /* cloned slave device handle */
249};
250
251#define PF_PKT 0x0008 /* packet mode */
252#define PF_STOPPED 0x0010 /* user told stopped */
253#define PF_REMOTE 0x0020 /* remote and flow controlled input */
254#define PF_NOSTOP 0x0040
255#define PF_UCNTL 0x0080 /* user control mode */
256#define PF_UNLOCKED 0x0100 /* slave unlock (master open resets) */
257#define PF_OPEN_M 0x0200 /* master is open */
258#define PF_OPEN_S 0x0400 /* slave is open */
259
260static int ptmx_clone(dev_t dev, int minor);
261
262int
263ptmx_init( __unused int config_count)
264{
265 /*
266 * We start looking at slot 10, since there are inits that will
267 * stomp explicit slots (e.g. vndevice stomps 1) below that.
268 */
269
270 /* Get a major number for /dev/ptmx */
271 if((ptmx_major = cdevsw_add(-15, &ptmx_cdev)) == -1) {
272 printf("ptmx_init: failed to obtain /dev/ptmx major number\n");
273 return (ENOENT);
274 }
275
276 /* Get a major number for /dev/pts/nnn */
277 if ((ptsd_major = cdevsw_add(-15, &ptsd_cdev)) == -1) {
278 (void)cdevsw_remove(ptmx_major, &ptmx_cdev);
279 printf("ptmx_init: failed to obtain /dev/ptmx major number\n");
280 return (ENOENT);
281 }
282
283 /* Create the /dev/ptmx device {<major>,0} */
284 (void)devfs_make_node_clone(makedev(ptmx_major, 0),
285 DEVFS_CHAR, UID_ROOT, GID_TTY, 0666,
286 ptmx_clone, PTMX_TEMPLATE);
287 return (0);
288}
289
290
291static struct _ptmx_ioctl_state {
292 struct ptmx_ioctl **pis_ioctl_list; /* pointer vector */
293 int pis_total; /* total slots */
294 int pis_free; /* free slots */
295} _state;
296#define PTMX_GROW_VECTOR 16 /* Grow by this many slots at a time */
297
298/*
299 * Given a minor number, return the corresponding structure for that minor
300 * number. If there isn't one, and the create flag is specified, we create
301 * one if possible.
302 *
303 * Parameters: minor Minor number of ptmx device
304 * open_flag PF_OPEN_M First open of master
305 * PF_OPEN_S First open of slave
306 * 0 Just want ioctl struct
307 *
308 * Returns: NULL Did not exist/could not create
309 * !NULL structure corresponding minor number
310 */
311static struct ptmx_ioctl *
312ptmx_get_ioctl(int minor, int open_flag)
313{
314 struct ptmx_ioctl *new_ptmx_ioctl;
315
316 if (open_flag & PF_OPEN_M) {
317
318 /*
319 * If we are about to allocate more memory, but we have
320 * already hit the administrative limit, then fail the
321 * operation.
322 *
323 * Note: Subtract free from total when making this
324 * check to allow unit increments, rather than
325 * snapping to the nearest PTMX_GROW_VECTOR...
326 */
327 if ((_state.pis_total - _state.pis_free) >= ptmx_max) {
328 return (NULL);
329 }
330
331 MALLOC(new_ptmx_ioctl, struct ptmx_ioctl *, sizeof(struct ptmx_ioctl), M_TTYS, M_WAITOK|M_ZERO);
332 if (new_ptmx_ioctl == NULL) {
333 return (NULL);
334 }
335
336 if ((new_ptmx_ioctl->pt_tty = ttymalloc()) == NULL) {
337 FREE(new_ptmx_ioctl, M_TTYS);
338 return (NULL);
339 }
340
341 /*
342 * Hold the DEVFS_LOCK() over this whole operation; devfs
343 * itself does this over malloc/free as well, so this should
344 * be safe to do. We hold it longer than we want to, but
345 * doing so avoids a reallocation race on the minor number.
346 */
347 DEVFS_LOCK();
348 /* Need to allocate a larger vector? */
349 if (_state.pis_free == 0) {
350 struct ptmx_ioctl **new_pis_ioctl_list;
351 struct ptmx_ioctl **old_pis_ioctl_list = NULL;
352
353 /* Yes. */
354 MALLOC(new_pis_ioctl_list, struct ptmx_ioctl **, sizeof(struct ptmx_ioctl *) * (_state.pis_total + PTMX_GROW_VECTOR), M_TTYS, M_WAITOK|M_ZERO);
355 if (new_pis_ioctl_list == NULL) {
356 ttyfree(new_ptmx_ioctl->pt_tty);
357 DEVFS_UNLOCK();
358 FREE(new_ptmx_ioctl, M_TTYS);
359 return (NULL);
360 }
361
362 /* If this is not the first time, copy the old over */
363 bcopy(_state.pis_ioctl_list, new_pis_ioctl_list, sizeof(struct ptmx_ioctl *) * _state.pis_total);
364 old_pis_ioctl_list = _state.pis_ioctl_list;
365 _state.pis_ioctl_list = new_pis_ioctl_list;
366 _state.pis_free += PTMX_GROW_VECTOR;
367 _state.pis_total += PTMX_GROW_VECTOR;
368 if (old_pis_ioctl_list)
369 FREE(old_pis_ioctl_list, M_TTYS);
370 }
371
372 /* Vector is large enough; grab a new ptmx_ioctl */
373
374 /* Now grab a free slot... */
375 _state.pis_ioctl_list[minor] = new_ptmx_ioctl;
376
377 /* reduce free count */
378 _state.pis_free--;
379
380 _state.pis_ioctl_list[minor]->pt_flags |= PF_OPEN_M;
381 DEVFS_UNLOCK();
382
383 /* Create the /dev/ttysXXX device {<major>,XXX} */
384 _state.pis_ioctl_list[minor]->pt_devhandle = devfs_make_node(
385 makedev(ptsd_major, minor),
386 DEVFS_CHAR, UID_ROOT, GID_TTY, 0620,
387 PTSD_TEMPLATE, minor);
388 } else if (open_flag & PF_OPEN_S) {
389 DEVFS_LOCK();
390 _state.pis_ioctl_list[minor]->pt_flags |= PF_OPEN_S;
391 DEVFS_UNLOCK();
392 }
393 return (_state.pis_ioctl_list[minor]);
394}
395
396static int
397ptmx_free_ioctl(int minor, int open_flag)
398{
399 struct ptmx_ioctl *old_ptmx_ioctl = NULL;
400
401 DEVFS_LOCK();
402#if 5161374
403 /*
404 * We have to check after taking the DEVFS_LOCK, since the pointer
405 * is protected by the lock
406 */
407 if (_state.pis_ioctl_list[minor] == NULL) {
408 DEVFS_UNLOCK();
409 return (ENXIO);
410 }
411#endif /* 5161374 */
412 _state.pis_ioctl_list[minor]->pt_flags &= ~(open_flag);
413
414 /*
415 * Was this the last close? We will recognize it because we only get
416 * a notification on the last close of a device, and we will have
417 * cleared both the master and the slave open bits in the flags.
418 */
419 if (!(_state.pis_ioctl_list[minor]->pt_flags & (PF_OPEN_M|PF_OPEN_S))) {
420 /* Mark as free so it can be reallocated later */
421 old_ptmx_ioctl = _state.pis_ioctl_list[ minor];
422 _state.pis_ioctl_list[ minor] = NULL;
423 _state.pis_free++;
424 }
425 DEVFS_UNLOCK();
426
427 /* Free old after dropping lock */
428 if (old_ptmx_ioctl != NULL) {
429 /*
430 * XXX See <rdar://5348651> and <rdar://4854638>
431 *
432 * XXX Conditional to be removed when/if tty/pty reference
433 * XXX counting and mutex implemented.
434 */
435 if (old_ptmx_ioctl->pt_devhandle != NULL)
436 devfs_remove(old_ptmx_ioctl->pt_devhandle);
437 ttyfree(old_ptmx_ioctl->pt_tty);
438 FREE(old_ptmx_ioctl, M_TTYS);
439 }
440
441 return (0); /* Success */
442}
443
444
445
446
447/*
448 * Given the dev entry that's being opened, we clone the device. This driver
449 * doesn't actually use the dev entry, since we alreaqdy know who we are by
450 * being called from this code. This routine is a callback registered from
451 * devfs_make_node_clone() in ptmx_init(); it's purpose is to provide a new
452 * minor number, or to return -1, if one can't be provided.
453 *
454 * Parameters: dev The device we are cloning from
455 *
456 * Returns: >= 0 A new minor device number
457 * -1 Error: ENOMEM ("Can't alloc device")
458 *
459 * NOTE: Called with DEVFS_LOCK() held
460 */
461static int
462ptmx_clone(__unused dev_t dev, int action)
463{
464 int i;
465
466 if (action == DEVFS_CLONE_ALLOC) {
467 /* First one */
468 if (_state.pis_total == 0)
469 return (0);
470
471 /*
472 * Note: We can add hinting on free slots, if this linear search
473 * ends up being a performance bottleneck...
474 */
475 for(i = 0; i < _state.pis_total; i++) {
476 if (_state.pis_ioctl_list[ i] == NULL)
477 break;
478 }
479
480 /*
481 * XXX We fall off the end here; if we did this twice at the
482 * XXX same time, we could return the same minor to two
483 * XXX callers; we should probably exand the pointer vector
484 * XXX here, but I need more information on the MALLOC/FREE
485 * XXX locking to ensure against a deadlock. Maybe we can
486 * XXX just high watermark it at 1/2 of PTMX_GROW_VECTOR?
487 * XXX That would require returning &minor as implict return
488 * XXX and an error code ("EAGAIN/ERESTART") or 0 as our
489 * XXX explicit return.
490 */
491
492 return (i); /* empty slot or next slot */
493 }
494 return(-1);
495}
496
497FREE_BSDSTATIC int
498ptsd_open(dev_t dev, int flag, __unused int devtype, __unused proc_t p)
499{
500 struct tty *tp;
501 struct ptmx_ioctl *pti;
502 int error;
503 boolean_t funnel_state;
504
505 if ((pti = ptmx_get_ioctl(minor(dev), 0)) == NULL) {
506 return (ENXIO);
507 }
508 tp = pti->pt_tty;
509
510 if (!(pti->pt_flags & PF_UNLOCKED)) {
511 return (EAGAIN);
512 }
513
514 funnel_state = thread_funnel_set(kernel_flock, TRUE);
515
516 if ((tp->t_state & TS_ISOPEN) == 0) {
517 ttychars(tp); /* Set up default chars */
518 tp->t_iflag = TTYDEF_IFLAG;
519 tp->t_oflag = TTYDEF_OFLAG;
520 tp->t_lflag = TTYDEF_LFLAG;
521 tp->t_cflag = TTYDEF_CFLAG;
522 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
523 ttsetwater(tp); /* would be done in xxparam() */
524 } else if (tp->t_state&TS_XCLUDE && suser(kauth_cred_get(), NULL)) {
525 error = EBUSY;
526 goto out;
527 }
528 if (tp->t_oproc) /* Ctrlr still around. */
529 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
530 while ((tp->t_state & TS_CARR_ON) == 0) {
531 if (flag&FNONBLOCK)
532 break;
533 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
534 "ptsd_opn", 0);
535 if (error)
536 goto out;
537 }
538 error = (*linesw[tp->t_line].l_open)(dev, tp);
539 /* Successful open; mark as open by the slave */
540 pti->pt_flags |= PF_OPEN_S;
541 if (error == 0)
542 ptmx_wakeup(tp, FREAD|FWRITE);
543out:
544 (void) thread_funnel_set(kernel_flock, funnel_state);
545 return (error);
546}
547
548FREE_BSDSTATIC int
549ptsd_close(dev_t dev, int flag, __unused int mode, __unused proc_t p)
550{
551 struct tty *tp;
552 struct ptmx_ioctl *pti;
553 int err;
554 boolean_t funnel_state;
555
556 /*
557 * This is temporary until the VSX conformance tests
558 * are fixed. They are hanging with a deadlock
559 * where close(ptsd) will not complete without t_timeout set
560 */
561#define FIX_VSX_HANG 1
562#ifdef FIX_VSX_HANG
563 int save_timeout;
564#endif
565 pti = ptmx_get_ioctl(minor(dev), 0);
566#if 5161374
567 if (pti == NULL || pti->pt_tty == NULL)
568 return(ENXIO);
569#endif /* 5161374 */
570 tp = pti->pt_tty;
571
572 funnel_state = thread_funnel_set(kernel_flock, TRUE);
573
574#ifdef FIX_VSX_HANG
575 save_timeout = tp->t_timeout;
576 tp->t_timeout = 60;
577#endif
578 err = (*linesw[tp->t_line].l_close)(tp, flag);
579 ptsd_stop(tp, FREAD|FWRITE);
580 (void) ttyclose(tp);
581#ifdef FIX_VSX_HANG
582 tp->t_timeout = save_timeout;
583#endif
584 (void) thread_funnel_set(kernel_flock, funnel_state);
585
586 /* unconditional, just like ttyclose() */
587 ptmx_free_ioctl(minor(dev), PF_OPEN_S);
588
589 return (err);
590}
591
592FREE_BSDSTATIC int
593ptsd_read(dev_t dev, struct uio *uio, int flag)
594{
595 proc_t p = current_proc();
596
597 struct tty *tp;
598 struct ptmx_ioctl *pti;
599 int error = 0;
600 struct uthread *ut;
601 boolean_t funnel_state;
602 struct pgrp * pg;
603
604 pti = ptmx_get_ioctl(minor(dev), 0);
605#if 5161374
606 if (pti == NULL || pti->pt_tty == NULL)
607 return(ENXIO);
608#endif /* 5161374 */
609 tp = pti->pt_tty;
610
611 funnel_state = thread_funnel_set(kernel_flock, TRUE);
612
613
614 ut = (struct uthread *)get_bsdthread_info(current_thread());
615again:
616 if (pti->pt_flags & PF_REMOTE) {
617 while (isbackground(p, tp)) {
618 if ((p->p_sigignore & sigmask(SIGTTIN)) ||
619 (ut->uu_sigmask & sigmask(SIGTTIN)) ||
620 p->p_lflag & P_LPPWAIT) {
621 error = EIO;
622 goto out;
623 }
624 pg = proc_pgrp(p);
625 if (pg == PGRP_NULL) {
626 error = EIO;
627 goto out;
628 }
629 if (pg->pg_jobc == 0) {
630 pg_rele(pg);
631 error = EIO;
632 goto out;
633 }
634 pgsignal(pg, SIGTTIN, 1);
635 pg_rele(pg);
636
637 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ptsd_bg",
638 0);
639 if (error)
640 goto out;
641 }
642 if (tp->t_canq.c_cc == 0) {
643 if (flag & IO_NDELAY)
644 return (EWOULDBLOCK);
645 error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
646 "ptsd_in", 0);
647 if (error)
648 goto out;
649 goto again;
650 }
651 while (tp->t_canq.c_cc > 1 && uio_resid(uio) > 0) {
652 int cc;
653 char buf[BUFSIZ];
654
655 cc = min(uio_resid(uio), BUFSIZ);
656 // Don't copy the very last byte
657 cc = min(cc, tp->t_canq.c_cc - 1);
658 cc = q_to_b(&tp->t_canq, (u_char *)buf, cc);
659 error = uiomove(buf, cc, uio);
660 if (error)
661 break;
662 }
663 if (tp->t_canq.c_cc == 1)
664 (void) getc(&tp->t_canq);
665 if (tp->t_canq.c_cc)
666 goto out;
667 } else
668 if (tp->t_oproc)
669 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
670 ptmx_wakeup(tp, FWRITE);
671out:
672 (void) thread_funnel_set(kernel_flock, funnel_state);
673 return (error);
674}
675
676/*
677 * Write to pseudo-tty.
678 * Wakeups of controlling tty will happen
679 * indirectly, when tty driver calls ptsd_start.
680 */
681FREE_BSDSTATIC int
682ptsd_write(dev_t dev, struct uio *uio, int flag)
683{
684 struct tty *tp;
685 struct ptmx_ioctl *pti;
686 int error;
687 boolean_t funnel_state;
688
689 funnel_state = thread_funnel_set(kernel_flock, TRUE);
690
691 pti = ptmx_get_ioctl(minor(dev), 0);
692#if 5161374
693 if (pti == NULL || pti->pt_tty == NULL)
694 return(ENXIO);
695#endif /* 5161374 */
696 tp = pti->pt_tty;
697
698 if (tp->t_oproc == 0)
699 error = EIO;
700 else
701 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
702
703 (void) thread_funnel_set(kernel_flock, funnel_state);
704 return (error);
705}
706
707/*
708 * Start output on pseudo-tty.
709 * Wake up process selecting or sleeping for input from controlling tty.
710 */
711static void
712ptsd_start(struct tty *tp)
713{
714 struct ptmx_ioctl *pti;
715 boolean_t funnel_state;
716
717 pti = ptmx_get_ioctl(minor(tp->t_dev), 0);
718#if 5161374
719 if (pti == NULL)
720 return; /* XXX ENXIO, but this function is void! */
721#endif /* 5161374 */
722
723 funnel_state = thread_funnel_set(kernel_flock, TRUE);
724
725 if (tp->t_state & TS_TTSTOP)
726 goto out;
727 if (pti->pt_flags & PF_STOPPED) {
728 pti->pt_flags &= ~PF_STOPPED;
729 pti->pt_send = TIOCPKT_START;
730 }
731 ptmx_wakeup(tp, FREAD);
732out:
733 (void) thread_funnel_set(kernel_flock, funnel_state);
734 return;
735}
736
737static void
738ptmx_wakeup(struct tty *tp, int flag)
739{
740 struct ptmx_ioctl *pti;
741 boolean_t funnel_state;
742
743 pti = ptmx_get_ioctl(minor(tp->t_dev), 0);
744#if 5161374
745 if (pti == NULL)
746 return; /* XXX ENXIO, but this function is void! */
747#endif /* 5161374 */
748
749 funnel_state = thread_funnel_set(kernel_flock, TRUE);
750
751 if (flag & FREAD) {
752 selwakeup(&pti->pt_selr);
753 wakeup(TSA_PTC_READ(tp));
754 }
755 if (flag & FWRITE) {
756 selwakeup(&pti->pt_selw);
757 wakeup(TSA_PTC_WRITE(tp));
758 }
759 (void) thread_funnel_set(kernel_flock, funnel_state);
760}
761
762FREE_BSDSTATIC int
763ptmx_open(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p)
764{
765 struct tty *tp;
766 struct ptmx_ioctl *pti;
767 int error = 0;
768 boolean_t funnel_state;
769
770
771 if ((pti = ptmx_get_ioctl(minor(dev), PF_OPEN_M)) == NULL) {
772 return (ENXIO);
773 }
774 tp = pti->pt_tty;
775
776 funnel_state = thread_funnel_set(kernel_flock, TRUE);
777
778 /* If master is open OR slave is still draining, pty is still busy */
779 if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) {
780 /*
781 * If master is closed, we are the only reference, so we
782 * need to clear the master open bit
783 */
784 if (!tp->t_oproc)
785 ptmx_free_ioctl(minor(dev), PF_OPEN_M);
786 error = EBUSY;
787 goto out;
788 }
789 tp->t_oproc = ptsd_start;
790 CLR(tp->t_state, TS_ZOMBIE);
791#ifdef sun4c
792 tp->t_stop = ptsd_stop;
793#endif
794 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
795 tp->t_lflag &= ~EXTPROC;
796
797out:
798 (void) thread_funnel_set(kernel_flock, funnel_state);
799 return (error);
800}
801
802FREE_BSDSTATIC int
803ptmx_close(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p)
804{
805 struct tty *tp;
806 struct ptmx_ioctl *pti;
807 boolean_t funnel_state;
808
809 pti = ptmx_get_ioctl(minor(dev), 0);
810#if 5161374
811 if (pti == NULL || pti->pt_tty == NULL)
812 return(ENXIO);
813#endif /* 5161374 */
814 tp = pti->pt_tty;
815
816 funnel_state = thread_funnel_set(kernel_flock, TRUE);
817
818 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
819
820 /*
821 * XXX MDMBUF makes no sense for ptys but would inhibit the above
822 * l_modem(). CLOCAL makes sense but isn't supported. Special
823 * l_modem()s that ignore carrier drop make no sense for ptys but
824 * may be in use because other parts of the line discipline make
825 * sense for ptys. Recover by doing everything that a normal
826 * ttymodem() would have done except for sending a SIGHUP.
827 */
828 if (tp->t_state & TS_ISOPEN) {
829 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
830 tp->t_state |= TS_ZOMBIE;
831 ttyflush(tp, FREAD | FWRITE);
832 }
833
834 tp->t_oproc = 0; /* mark closed */
835
836 (void) thread_funnel_set(kernel_flock, funnel_state);
837
838 ptmx_free_ioctl(minor(dev), PF_OPEN_M);
839
840 return (0);
841}
842
843FREE_BSDSTATIC int
844ptmx_read(dev_t dev, struct uio *uio, int flag)
845{
846 struct tty *tp;
847 struct ptmx_ioctl *pti;
848 char buf[BUFSIZ];
849 int error = 0, cc;
850 boolean_t funnel_state;
851
852 pti = ptmx_get_ioctl(minor(dev), 0);
853#if 5161374
854 if (pti == NULL || pti->pt_tty == NULL)
855 return(ENXIO);
856#endif /* 5161374 */
857 tp = pti->pt_tty;
858
859 funnel_state = thread_funnel_set(kernel_flock, TRUE);
860
861 /*
862 * We want to block until the slave
863 * is open, and there's something to read;
864 * but if we lost the slave or we're NBIO,
865 * then return the appropriate error instead.
866 */
867 for (;;) {
868 if (tp->t_state&TS_ISOPEN) {
869 if (pti->pt_flags & PF_PKT && pti->pt_send) {
870 error = ureadc((int)pti->pt_send, uio);
871 if (error)
872 goto out;
873 if (pti->pt_send & TIOCPKT_IOCTL) {
874 cc = min(uio_resid(uio),
875 sizeof(tp->t_termios));
876 uiomove((caddr_t)&tp->t_termios, cc,
877 uio);
878 }
879 pti->pt_send = 0;
880 goto out;
881 }
882 if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
883 error = ureadc((int)pti->pt_ucntl, uio);
884 if (error)
885 goto out;
886 pti->pt_ucntl = 0;
887 goto out;
888 }
889 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
890 break;
891 }
892 if ((tp->t_state & TS_CONNECTED) == 0)
893 goto out; /* EOF */
894 if (flag & IO_NDELAY) {
895 error = EWOULDBLOCK;
896 goto out;
897 }
898 error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptmx_in", 0);
899 if (error)
900 goto out;
901 }
902 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
903 error = ureadc(0, uio);
904 while (uio_resid(uio) > 0 && error == 0) {
905 cc = q_to_b(&tp->t_outq, (u_char *)buf, min(uio_resid(uio), BUFSIZ));
906 if (cc <= 0)
907 break;
908 error = uiomove(buf, cc, uio);
909 }
910 (*linesw[tp->t_line].l_start)(tp);
911
912out:
913 (void) thread_funnel_set(kernel_flock, funnel_state);
914 return (error);
915}
916
917FREE_BSDSTATIC int
918ptsd_stop(struct tty *tp, int flush)
919{
920 struct ptmx_ioctl *pti;
921 int flag;
922 boolean_t funnel_state;
923
924 pti = ptmx_get_ioctl(minor(tp->t_dev), 0);
925#if 5161374
926 if (pti == NULL)
927 return(ENXIO);
928#endif /* 5161374 */
929
930 funnel_state = thread_funnel_set(kernel_flock, TRUE);
931
932 /* note: FLUSHREAD and FLUSHWRITE already ok */
933 if (flush == 0) {
934 flush = TIOCPKT_STOP;
935 pti->pt_flags |= PF_STOPPED;
936 } else
937 pti->pt_flags &= ~PF_STOPPED;
938 pti->pt_send |= flush;
939 /* change of perspective */
940 flag = 0;
941 if (flush & FREAD)
942 flag |= FWRITE;
943 if (flush & FWRITE)
944 flag |= FREAD;
945 ptmx_wakeup(tp, flag);
946
947 (void) thread_funnel_set(kernel_flock, funnel_state);
948
949 return (0);
950}
951
952FREE_BSDSTATIC int
953ptsd_reset(__unused int uban)
954{
955 return (0);
956}
957
958/*
959 * Reinput pending characters after state switch
960 * call at spltty().
961 *
962 * XXX Code duplication: static function, should be inlined
963 */
964static void
965ttypend(struct tty *tp)
966{
967 struct clist tq;
968 int c;
969
970 CLR(tp->t_lflag, PENDIN);
971 SET(tp->t_state, TS_TYPEN);
972 tq = tp->t_rawq;
973 tp->t_rawq.c_cc = 0;
974 tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
975 while ((c = getc(&tq)) >= 0)
976 ttyinput(c, tp);
977 CLR(tp->t_state, TS_TYPEN);
978}
979
980/*
981 * Must be called at spltty().
982 *
983 * XXX Code duplication: static function, should be inlined
984 */
985static int
986ttnread(struct tty *tp)
987{
988 int nread;
989
990 if (ISSET(tp->t_lflag, PENDIN))
991 ttypend(tp);
992 nread = tp->t_canq.c_cc;
993 if (!ISSET(tp->t_lflag, ICANON)) {
994 nread += tp->t_rawq.c_cc;
995 if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
996 nread = 0;
997 }
998 return (nread);
999}
1000
1001int
1002ptsd_select(dev_t dev, int rw, void *wql, proc_t p)
1003{
1004 struct ptmx_ioctl *pti;
1005 struct tty *tp;
1006
1007 pti = ptmx_get_ioctl(minor(dev), 0);
1008#if 5161374
1009 if (pti == NULL || pti->pt_tty == NULL)
1010 return(ENXIO);
1011#endif /* 5161374 */
1012 tp = pti->pt_tty;
1013
1014 if (tp == NULL)
1015 return (ENXIO);
1016
1017 switch (rw) {
1018 case FREAD:
1019 if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE))
1020 return(1);
1021 selrecord(p, &tp->t_rsel, wql);
1022 break;
1023 case FWRITE:
1024 if ((tp->t_outq.c_cc <= tp->t_lowat &&
1025 ISSET(tp->t_state, TS_CONNECTED))
1026 || ISSET(tp->t_state, TS_ZOMBIE)) {
1027 return (1);
1028 }
1029 selrecord(p, &tp->t_wsel, wql);
1030 break;
1031 }
1032 return (0);
1033}
1034
1035FREE_BSDSTATIC int
1036ptmx_select(dev_t dev, int rw, void *wql, proc_t p)
1037{
1038 struct tty *tp;
1039 struct ptmx_ioctl *pti;
1040 int retval = 0;
1041 boolean_t funnel_state;
1042
1043 pti = ptmx_get_ioctl(minor(dev), 0);
1044#if 5161374
1045 if (pti == NULL || pti->pt_tty == NULL)
1046 return(ENXIO);
1047#endif /* 5161374 */
1048 tp = pti->pt_tty;
1049
1050 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1051
1052 if ((tp->t_state & TS_CONNECTED) == 0) {
1053 retval = 1;
1054 goto out;
1055 }
1056 switch (rw) {
1057
1058 case FREAD:
1059 /*
1060 * Need to block timeouts (ttrstart).
1061 */
1062 if ((tp->t_state&TS_ISOPEN) &&
1063 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
1064 retval = 1;
1065 goto out;
1066 }
1067 /* FALLTHROUGH */
1068
1069 case 0: /* exceptional */
1070 if ((tp->t_state&TS_ISOPEN) &&
1071 ((pti->pt_flags & PF_PKT && pti->pt_send) ||
1072 (pti->pt_flags & PF_UCNTL && pti->pt_ucntl))) {
1073 retval = 1;
1074 goto out;
1075 }
1076 selrecord(p, &pti->pt_selr, wql);
1077 break;
1078
1079
1080 case FWRITE:
1081 if (tp->t_state&TS_ISOPEN) {
1082 if (pti->pt_flags & PF_REMOTE) {
1083 if (tp->t_canq.c_cc == 0) {
1084 retval = 1;
1085 goto out;
1086 }
1087 } else {
1088 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) {
1089 retval = 1;
1090 goto out;
1091 }
1092 if (tp->t_canq.c_cc == 0 && (tp->t_lflag&ICANON)) {
1093 retval = 1;
1094 goto out;
1095 }
1096 }
1097 }
1098 selrecord(p, &pti->pt_selw, wql);
1099 break;
1100
1101 }
1102out:
1103 (void) thread_funnel_set(kernel_flock, funnel_state);
1104 return (retval);
1105}
1106
1107FREE_BSDSTATIC int
1108ptmx_stop(__unused struct tty *tp, __unused int flush)
1109{
1110 return (0);
1111}
1112
1113FREE_BSDSTATIC int
1114ptmx_reset(__unused int uban)
1115{
1116 return (0);
1117}
1118
1119FREE_BSDSTATIC int
1120ptmx_write(dev_t dev, struct uio *uio, int flag)
1121{
1122 struct tty *tp;
1123 struct ptmx_ioctl *pti;
1124 u_char *cp = NULL;
1125 int cc = 0;
1126 u_char locbuf[BUFSIZ];
1127 int wcnt = 0;
1128 int error = 0;
1129 boolean_t funnel_state;
1130
1131 pti = ptmx_get_ioctl(minor(dev), 0);
1132#if 5161374
1133 if (pti == NULL || pti->pt_tty == NULL)
1134 return(ENXIO);
1135#endif /* 5161374 */
1136 tp = pti->pt_tty;
1137
1138 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1139
1140again:
1141 if ((tp->t_state&TS_ISOPEN) == 0)
1142 goto block;
1143 if (pti->pt_flags & PF_REMOTE) {
1144 if (tp->t_canq.c_cc)
1145 goto block;
1146 while ((uio_resid(uio) > 0 || cc > 0) &&
1147 tp->t_canq.c_cc < TTYHOG - 1) {
1148 if (cc == 0) {
1149 cc = min(uio_resid(uio), BUFSIZ);
1150 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
1151 cp = locbuf;
1152 error = uiomove((caddr_t)cp, cc, uio);
1153 if (error)
1154 goto out;
1155 /* check again for safety */
1156 if ((tp->t_state & TS_ISOPEN) == 0) {
1157 /* adjust as usual */
1158 uio_setresid(uio, (uio_resid(uio) + cc));
1159 error = EIO;
1160 goto out;
1161 }
1162 }
1163 if (cc > 0) {
1164 cc = b_to_q((u_char *)cp, cc, &tp->t_canq);
1165 /*
1166 * XXX we don't guarantee that the canq size
1167 * is >= TTYHOG, so the above b_to_q() may
1168 * leave some bytes uncopied. However, space
1169 * is guaranteed for the null terminator if
1170 * we don't fail here since (TTYHOG - 1) is
1171 * not a multiple of CBSIZE.
1172 */
1173 if (cc > 0)
1174 break;
1175 }
1176 }
1177 /* adjust for data copied in but not written */
1178 uio_setresid(uio, (uio_resid(uio) + cc));
1179 (void) putc(0, &tp->t_canq);
1180 ttwakeup(tp);
1181 wakeup(TSA_PTS_READ(tp));
1182 goto out;
1183 }
1184 while (uio_resid(uio) > 0 || cc > 0) {
1185 if (cc == 0) {
1186 cc = min(uio_resid(uio), BUFSIZ);
1187 cp = locbuf;
1188 error = uiomove((caddr_t)cp, cc, uio);
1189 if (error)
1190 goto out;
1191 /* check again for safety */
1192 if ((tp->t_state & TS_ISOPEN) == 0) {
1193 /* adjust for data copied in but not written */
1194 uio_setresid(uio, (uio_resid(uio) + cc));
1195 error = EIO;
1196 goto out;
1197 }
1198 }
1199 while (cc > 0) {
1200 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
1201 (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
1202 wakeup(TSA_HUP_OR_INPUT(tp));
1203 goto block;
1204 }
1205 (*linesw[tp->t_line].l_rint)(*cp++, tp);
1206 wcnt++;
1207 cc--;
1208 }
1209 cc = 0;
1210 }
1211out:
1212 (void) thread_funnel_set(kernel_flock, funnel_state);
1213 return (error);
1214block:
1215 /*
1216 * Come here to wait for slave to open, for space
1217 * in outq, or space in rawq, or an empty canq.
1218 */
1219 if ((tp->t_state & TS_CONNECTED) == 0) {
1220 /* adjust for data copied in but not written */
1221 uio_setresid(uio, (uio_resid(uio) + cc));
1222 error = EIO;
1223 goto out;
1224 }
1225 if (flag & IO_NDELAY) {
1226 /* adjust for data copied in but not written */
1227 uio_setresid(uio, (uio_resid(uio) + cc));
1228 if (wcnt == 0)
1229 error = EWOULDBLOCK;
1230 goto out;
1231 }
1232 error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptmx_out", 0);
1233 if (error) {
1234 /* adjust for data copied in but not written */
1235 uio_setresid(uio, (uio_resid(uio) + cc));
1236 goto out;
1237 }
1238 goto again;
1239}
1240
1241
1242FREE_BSDSTATIC int
1243cptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, proc_t p)
1244{
1245 struct tty *tp;
1246 struct ptmx_ioctl *pti;
1247 u_char *cc;
1248 int stop, error = 0;
1249 boolean_t funnel_state;
1250
1251 pti = ptmx_get_ioctl(minor(dev), 0);
1252#if 5161374
1253 if (pti == NULL || pti->pt_tty == NULL)
1254 return(ENXIO);
1255#endif /* 5161374 */
1256 tp = pti->pt_tty;
1257 cc = tp->t_cc;
1258
1259 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1260
1261 /*
1262 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
1263 * ttywflush(tp) will hang if there are characters in the outq.
1264 */
1265 if (cmd == TIOCEXT) {
1266 /*
1267 * When the EXTPROC bit is being toggled, we need
1268 * to send an TIOCPKT_IOCTL if the packet driver
1269 * is turned on.
1270 */
1271 if (*(int *)data) {
1272 if (pti->pt_flags & PF_PKT) {
1273 pti->pt_send |= TIOCPKT_IOCTL;
1274 ptmx_wakeup(tp, FREAD);
1275 }
1276 tp->t_lflag |= EXTPROC;
1277 } else {
1278 if ((tp->t_lflag & EXTPROC) &&
1279 (pti->pt_flags & PF_PKT)) {
1280 pti->pt_send |= TIOCPKT_IOCTL;
1281 ptmx_wakeup(tp, FREAD);
1282 }
1283 tp->t_lflag &= ~EXTPROC;
1284 }
1285 goto out;
1286 } else
1287 if (cdevsw[major(dev)].d_open == ptmx_open)
1288 switch (cmd) {
1289
1290 case TIOCGPGRP:
1291 /*
1292 * We aviod calling ttioctl on the controller since,
1293 * in that case, tp must be the controlling terminal.
1294 */
1295 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
1296 goto out;
1297
1298 case TIOCPKT:
1299 if (*(int *)data) {
1300 if (pti->pt_flags & PF_UCNTL) {
1301 error = EINVAL;
1302 goto out;
1303 }
1304 pti->pt_flags |= PF_PKT;
1305 } else
1306 pti->pt_flags &= ~PF_PKT;
1307 goto out;
1308
1309 case TIOCUCNTL:
1310 if (*(int *)data) {
1311 if (pti->pt_flags & PF_PKT) {
1312 error = EINVAL;
1313 goto out;
1314 }
1315 pti->pt_flags |= PF_UCNTL;
1316 } else
1317 pti->pt_flags &= ~PF_UCNTL;
1318 goto out;
1319
1320 case TIOCREMOTE:
1321 if (*(int *)data)
1322 pti->pt_flags |= PF_REMOTE;
1323 else
1324 pti->pt_flags &= ~PF_REMOTE;
1325 ttyflush(tp, FREAD|FWRITE);
1326 goto out;
1327
1328#if COMPAT_43_TTY
1329 case TIOCSETP:
1330 case TIOCSETN:
1331#endif
1332 case TIOCSETD:
1333 case TIOCSETA:
1334 case TIOCSETAW:
1335 case TIOCSETAF:
1336 ndflush(&tp->t_outq, tp->t_outq.c_cc);
1337 break;
1338
1339 case TIOCSIG:
1340 if (*(unsigned int *)data >= NSIG ||
1341 *(unsigned int *)data == 0) {
1342 error = EINVAL;
1343 goto out;
1344 }
1345 if ((tp->t_lflag&NOFLSH) == 0)
1346 ttyflush(tp, FREAD|FWRITE);
1347 tty_pgsignal(tp, *(unsigned int *)data, 1);
1348 if ((*(unsigned int *)data == SIGINFO) &&
1349 ((tp->t_lflag&NOKERNINFO) == 0))
1350 ttyinfo(tp);
1351 goto out;
1352
1353 case TIOCPTYGRANT: /* grantpt(3) */
1354 /*
1355 * Change the uid of the slave to that of the calling
1356 * thread, change the gid of the slave to GID_TTY,
1357 * change the mode to 0620 (rw--w----).
1358 */
1359 {
1360 error = _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY);
1361 goto out;
1362 }
1363
1364 case TIOCPTYGNAME: /* ptsname(3) */
1365 /*
1366 * Report the name of the slave device in *data
1367 * (128 bytes max.). Use the same template string
1368 * used for calling devfs_make_node() to create it.
1369 */
1370 snprintf(data, 128, "/dev/" PTSD_TEMPLATE, minor(dev));
1371 error = 0;
1372 goto out;
1373
1374 case TIOCPTYUNLK: /* unlockpt(3) */
1375 /*
1376 * Unlock the slave device so that it can be opened.
1377 */
1378 pti->pt_flags |= PF_UNLOCKED;
1379 error = 0;
1380 goto out;
1381 }
1382 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1383 if (error == ENOTTY) {
1384 error = ttioctl(tp, cmd, data, flag, p);
1385 if (error == ENOTTY) {
1386 if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) {
1387 /* Process the UIOCMD ioctl group */
1388 if (cmd & 0xff) {
1389 pti->pt_ucntl = (u_char)cmd;
1390 ptmx_wakeup(tp, FREAD);
1391 }
1392 error = 0;
1393 goto out;
1394 } else if (cmd == TIOCSBRK || cmd == TIOCCBRK) {
1395 /*
1396 * POSIX conformance; rdar://3936338
1397 *
1398 * Clear ENOTTY in the case of setting or
1399 * clearing a break failing because pty's
1400 * don't support break like real serial
1401 * ports.
1402 */
1403 error = 0;
1404 goto out;
1405 }
1406 }
1407 }
1408
1409 /*
1410 * If external processing and packet mode send ioctl packet.
1411 */
1412 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
1413 switch(cmd) {
1414 case TIOCSETA:
1415 case TIOCSETAW:
1416 case TIOCSETAF:
1417#if COMPAT_43_TTY
1418 case TIOCSETP:
1419 case TIOCSETN:
1420#endif
1421#if COMPAT_43_TTY || defined(COMPAT_SUNOS)
1422 case TIOCSETC:
1423 case TIOCSLTC:
1424 case TIOCLBIS:
1425 case TIOCLBIC:
1426 case TIOCLSET:
1427#endif
1428 pti->pt_send |= TIOCPKT_IOCTL;
1429 ptmx_wakeup(tp, FREAD);
1430 default:
1431 break;
1432 }
1433 }
1434 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
1435 && CCEQ(cc[VSTART], CTRL('q'));
1436 if (pti->pt_flags & PF_NOSTOP) {
1437 if (stop) {
1438 pti->pt_send &= ~TIOCPKT_NOSTOP;
1439 pti->pt_send |= TIOCPKT_DOSTOP;
1440 pti->pt_flags &= ~PF_NOSTOP;
1441 ptmx_wakeup(tp, FREAD);
1442 }
1443 } else {
1444 if (!stop) {
1445 pti->pt_send &= ~TIOCPKT_DOSTOP;
1446 pti->pt_send |= TIOCPKT_NOSTOP;
1447 pti->pt_flags |= PF_NOSTOP;
1448 ptmx_wakeup(tp, FREAD);
1449 }
1450 }
1451out:
1452 (void) thread_funnel_set(kernel_flock, funnel_state);
1453 return (error);
1454}