]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/tty_pty.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / bsd / kern / tty_pty.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 1997-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b
A
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>
91447636
A
72#include <sys/proc_internal.h>
73#include <sys/kauth.h>
1c79356b
A
74#include <sys/tty.h>
75#include <sys/conf.h>
91447636 76#include <sys/file_internal.h>
b0d623f7 77#include <sys/uio_internal.h>
1c79356b
A
78#include <sys/kernel.h>
79#include <sys/vnode.h>
9bccf70c 80#include <sys/user.h>
1c79356b
A
81#include <sys/signalvar.h>
82
1c79356b 83#define d_devtotty_t struct tty **
55e303ae
A
84
85#ifdef d_stop_t
86#undef d_stop_t
87#endif
91447636 88typedef void d_stop_t(struct tty *tp, int rw);
55e303ae 89
91447636
A
90/* XXX function should be removed??? */
91int pty_init(int n_ptys);
92
2d21ac55
A
93/* XXX should be a devfs function */
94int _devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid);
95
91447636
A
96static void ptsstart(struct tty *tp);
97static void ptcwakeup(struct tty *tp, int flag);
1c79356b 98
2d21ac55
A
99__private_extern__ d_open_t ptsopen;
100__private_extern__ d_close_t ptsclose;
101__private_extern__ d_read_t ptsread;
102__private_extern__ d_write_t ptswrite;
103__private_extern__ d_ioctl_t ptyioctl;
104__private_extern__ d_stop_t ptsstop;
105__private_extern__ d_devtotty_t ptydevtotty;
106__private_extern__ d_open_t ptcopen;
107__private_extern__ d_close_t ptcclose;
108__private_extern__ d_read_t ptcread;
109__private_extern__ d_write_t ptcwrite;
110__private_extern__ d_select_t ptcselect;
1c79356b
A
111
112#if NPTY == 1
113#undef NPTY
114#define NPTY 32 /* crude XXX */
115#warning You have only one pty defined, redefining to 32.
116#endif
117
1c79356b
A
118#define BUFSIZ 100 /* Chunk size iomoved to/from user */
119
120/*
121 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
122 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
123 */
2d21ac55
A
124/* All references to have been changed to indirections in the file */
125__private_extern__ struct tty *pt_tty[NPTY] = { NULL };
1c79356b
A
126
127static struct pt_ioctl {
128 int pt_flags;
129 struct selinfo pt_selr, pt_selw;
130 u_char pt_send;
131 u_char pt_ucntl;
2d21ac55 132 void *pt_devhandle; /* slave device handle for grantpt() */
1c79356b
A
133} pt_ioctl[NPTY]; /* XXX */
134static int npty = NPTY; /* for pstat -t */
135
136#define PF_PKT 0x08 /* packet mode */
137#define PF_STOPPED 0x10 /* user told stopped */
138#define PF_REMOTE 0x20 /* remote and flow controlled input */
139#define PF_NOSTOP 0x40
140#define PF_UCNTL 0x80 /* user control mode */
141
1c79356b 142#ifndef DEVFS
91447636
A
143int
144pty_init(__unused int n_ptys)
1c79356b
A
145{
146 return 0;
147}
148#else
149#include <miscfs/devfs/devfs.h>
150#define START_CHAR 'p'
151#define HEX_BASE 16
91447636
A
152int
153pty_init(int n_ptys)
1c79356b
A
154{
155 int i;
156 int j;
157
158 /* create the pseudo tty device nodes */
159 for (j = 0; j < 10; j++) {
160 for (i = 0; i < HEX_BASE; i++) {
161 int m = j * HEX_BASE + i;
162 if (m == n_ptys)
163 goto done;
2d21ac55 164 pt_ioctl[m].pt_devhandle = devfs_make_node(makedev(4, m),
1c79356b
A
165 DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
166 "tty%c%x", j + START_CHAR, i);
167 (void)devfs_make_node(makedev(5, m),
168 DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
169 "pty%c%x", j + START_CHAR, i);
170 }
171 }
172 done:
173 return (0);
174}
55e303ae 175#endif /* DEVFS */
1c79356b 176
2d21ac55 177__private_extern__ int
91447636 178ptsopen(dev_t dev, int flag, __unused int devtype, __unused struct proc *p)
1c79356b 179{
2d21ac55 180 struct tty *tp;
1c79356b
A
181 int error;
182
1c79356b 183 /*
91447636 184 * You will see this sort of code coming up in diffs later both
1c79356b
A
185 * the ttymalloc and the tp indirection.
186 */
91447636
A
187 if (minor(dev) >= npty) {
188 error = ENXIO;
b0d623f7 189 goto err;
91447636 190 }
1c79356b 191 if (!pt_tty[minor(dev)]) {
2d21ac55
A
192 /*
193 * If we can't allocate a new one, act as if we had run out
194 * of device nodes.
195 */
196 if ((tp = pt_tty[minor(dev)] = ttymalloc()) == NULL) {
197 error = ENXIO;
b0d623f7 198 goto err;
2d21ac55 199 }
1c79356b
A
200 } else
201 tp = pt_tty[minor(dev)];
b0d623f7
A
202
203 tty_lock(tp);
204
1c79356b 205 if ((tp->t_state & TS_ISOPEN) == 0) {
b0d623f7 206 termioschars(&tp->t_termios); /* Set up default chars */
1c79356b
A
207 tp->t_iflag = TTYDEF_IFLAG;
208 tp->t_oflag = TTYDEF_OFLAG;
209 tp->t_lflag = TTYDEF_LFLAG;
210 tp->t_cflag = TTYDEF_CFLAG;
211 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
212 ttsetwater(tp); /* would be done in xxparam() */
91447636
A
213 } else if (tp->t_state&TS_XCLUDE && suser(kauth_cred_get(), NULL)) {
214 error = EBUSY;
215 goto out;
216 }
1c79356b
A
217 if (tp->t_oproc) /* Ctrlr still around. */
218 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
219 while ((tp->t_state & TS_CARR_ON) == 0) {
220 if (flag&FNONBLOCK)
221 break;
222 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
223 "ptsopn", 0);
224 if (error)
91447636 225 goto out;
1c79356b
A
226 }
227 error = (*linesw[tp->t_line].l_open)(dev, tp);
228 if (error == 0)
229 ptcwakeup(tp, FREAD|FWRITE);
b0d623f7 230
91447636 231out:
b0d623f7
A
232 tty_unlock(tp);
233err:
1c79356b
A
234 return (error);
235}
236
2d21ac55 237__private_extern__ int
91447636 238ptsclose(dev_t dev, int flag, __unused int mode, __unused proc_t p)
1c79356b 239{
2d21ac55 240 struct tty *tp;
1c79356b 241 int err;
b0d623f7 242
2d21ac55
A
243 /*
244 * This is temporary until the VSX conformance tests
245 * are fixed. They are hanging with a deadlock
246 * where close(pts) will not complete without t_timeout set
247 */
248#define FIX_VSX_HANG 1
249#ifdef FIX_VSX_HANG
250 int save_timeout;
251#endif
1c79356b
A
252
253 tp = pt_tty[minor(dev)];
b0d623f7 254 tty_lock(tp);
2d21ac55
A
255#ifdef FIX_VSX_HANG
256 save_timeout = tp->t_timeout;
257 tp->t_timeout = 60;
258#endif
1c79356b
A
259 err = (*linesw[tp->t_line].l_close)(tp, flag);
260 ptsstop(tp, FREAD|FWRITE);
261 (void) ttyclose(tp);
2d21ac55
A
262#ifdef FIX_VSX_HANG
263 tp->t_timeout = save_timeout;
264#endif
b0d623f7 265 tty_unlock(tp);
1c79356b
A
266 return (err);
267}
268
2d21ac55
A
269__private_extern__ int
270ptsread(dev_t dev, struct uio *uio, int flag)
1c79356b 271{
1c79356b 272 struct proc *p = current_proc();
2d21ac55
A
273 struct tty *tp = pt_tty[minor(dev)];
274 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
1c79356b 275 int error = 0;
9bccf70c 276 struct uthread *ut;
2d21ac55 277 struct pgrp *pg;
1c79356b 278
b0d623f7 279 tty_lock(tp);
91447636
A
280
281 ut = (struct uthread *)get_bsdthread_info(current_thread());
1c79356b
A
282again:
283 if (pti->pt_flags & PF_REMOTE) {
284 while (isbackground(p, tp)) {
285 if ((p->p_sigignore & sigmask(SIGTTIN)) ||
9bccf70c 286 (ut->uu_sigmask & sigmask(SIGTTIN)) ||
2d21ac55 287 p->p_lflag & P_LPPWAIT) {
91447636
A
288 error = EIO;
289 goto out;
290 }
2d21ac55
A
291
292
293 pg = proc_pgrp(p);
294 if (pg == PGRP_NULL) {
295 error = EIO;
296 goto out;
297 }
b0d623f7
A
298 /*
299 * SAFE: We about to drop the lock ourselves by
300 * SAFE: erroring out or sleeping anyway.
301 */
302 tty_unlock(tp);
2d21ac55
A
303 if (pg->pg_jobc == 0) {
304 pg_rele(pg);
b0d623f7 305 tty_lock(tp);
2d21ac55
A
306 error = EIO;
307 goto out;
308 }
309 pgsignal(pg, SIGTTIN, 1);
310 pg_rele(pg);
b0d623f7 311 tty_lock(tp);
2d21ac55 312
1c79356b
A
313 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ptsbg",
314 0);
315 if (error)
91447636 316 goto out;
1c79356b
A
317 }
318 if (tp->t_canq.c_cc == 0) {
b0d623f7
A
319 if (flag & IO_NDELAY) {
320 error = EWOULDBLOCK;
321 goto out;
322 }
1c79356b
A
323 error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
324 "ptsin", 0);
325 if (error)
91447636 326 goto out;
1c79356b
A
327 goto again;
328 }
91447636
A
329 while (tp->t_canq.c_cc > 1 && uio_resid(uio) > 0) {
330 int cc;
331 char buf[BUFSIZ];
332
333 cc = min(uio_resid(uio), BUFSIZ);
334 // Don't copy the very last byte
335 cc = min(cc, tp->t_canq.c_cc - 1);
2d21ac55 336 cc = q_to_b(&tp->t_canq, (u_char *)buf, cc);
91447636
A
337 error = uiomove(buf, cc, uio);
338 if (error)
1c79356b 339 break;
91447636 340 }
1c79356b
A
341 if (tp->t_canq.c_cc == 1)
342 (void) getc(&tp->t_canq);
343 if (tp->t_canq.c_cc)
91447636 344 goto out;
1c79356b
A
345 } else
346 if (tp->t_oproc)
347 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
348 ptcwakeup(tp, FWRITE);
91447636 349out:
b0d623f7 350 tty_unlock(tp);
1c79356b
A
351 return (error);
352}
353
354/*
355 * Write to pseudo-tty.
356 * Wakeups of controlling tty will happen
357 * indirectly, when tty driver calls ptsstart.
358 */
2d21ac55
A
359__private_extern__ int
360ptswrite(dev_t dev, struct uio *uio, int flag)
1c79356b 361{
2d21ac55 362 struct tty *tp;
91447636 363 int error;
1c79356b
A
364
365 tp = pt_tty[minor(dev)];
b0d623f7
A
366
367 tty_lock(tp);
368
1c79356b 369 if (tp->t_oproc == 0)
91447636
A
370 error = EIO;
371 else
372 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
373
b0d623f7
A
374 tty_unlock(tp);
375
91447636 376 return (error);
1c79356b
A
377}
378
379/*
380 * Start output on pseudo-tty.
381 * Wake up process selecting or sleeping for input from controlling tty.
b0d623f7
A
382 *
383 * t_oproc for this driver; called from within the line discipline
384 *
385 * Locks: Assumes tp is locked on entry, remains locked on exit
1c79356b
A
386 */
387static void
2d21ac55 388ptsstart(struct tty *tp)
1c79356b 389{
2d21ac55 390 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1c79356b
A
391
392 if (tp->t_state & TS_TTSTOP)
91447636 393 goto out;
1c79356b
A
394 if (pti->pt_flags & PF_STOPPED) {
395 pti->pt_flags &= ~PF_STOPPED;
396 pti->pt_send = TIOCPKT_START;
397 }
398 ptcwakeup(tp, FREAD);
91447636 399out:
91447636 400 return;
1c79356b
A
401}
402
b0d623f7
A
403/*
404 * Locks: Assumes tty_lock() is held over this call.
405 */
1c79356b 406static void
2d21ac55 407ptcwakeup(struct tty *tp, int flag)
1c79356b
A
408{
409 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
410
411 if (flag & FREAD) {
412 selwakeup(&pti->pt_selr);
413 wakeup(TSA_PTC_READ(tp));
414 }
415 if (flag & FWRITE) {
416 selwakeup(&pti->pt_selw);
417 wakeup(TSA_PTC_WRITE(tp));
418 }
419}
420
2d21ac55 421__private_extern__ int
91447636 422ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p)
1c79356b 423{
2d21ac55 424 struct tty *tp;
1c79356b 425 struct pt_ioctl *pti;
91447636 426 int error = 0;
91447636
A
427
428 if (minor(dev) >= npty) {
429 error = ENXIO;
430 goto out;
431 }
1c79356b
A
432 if(!pt_tty[minor(dev)]) {
433 tp = pt_tty[minor(dev)] = ttymalloc();
434 } else
435 tp = pt_tty[minor(dev)];
b0d623f7
A
436
437 tty_lock(tp);
438
2d21ac55
A
439 /* If master is open OR slave is still draining, pty is still busy */
440 if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) {
441 error = EBUSY;
b0d623f7
A
442 } else {
443 tp->t_oproc = ptsstart;
444 CLR(tp->t_state, TS_ZOMBIE);
1c79356b 445#ifdef sun4c
b0d623f7 446 tp->t_stop = ptsstop;
1c79356b 447#endif
b0d623f7
A
448 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
449 tp->t_lflag &= ~EXTPROC;
450 pti = &pt_ioctl[minor(dev)];
451 pti->pt_flags = 0;
452 pti->pt_send = 0;
453 pti->pt_ucntl = 0;
454 }
455
456 tty_unlock(tp);
457
91447636 458out:
91447636 459 return (error);
1c79356b
A
460}
461
2d21ac55 462__private_extern__ int
91447636 463ptcclose(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p)
1c79356b 464{
b0d623f7 465 struct tty *tp = pt_tty[minor(dev)];
91447636 466
b0d623f7 467 tty_lock(tp);
1c79356b 468
1c79356b
A
469 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
470
471 /*
472 * XXX MDMBUF makes no sense for ptys but would inhibit the above
473 * l_modem(). CLOCAL makes sense but isn't supported. Special
474 * l_modem()s that ignore carrier drop make no sense for ptys but
475 * may be in use because other parts of the line discipline make
476 * sense for ptys. Recover by doing everything that a normal
477 * ttymodem() would have done except for sending a SIGHUP.
478 */
479 if (tp->t_state & TS_ISOPEN) {
480 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
481 tp->t_state |= TS_ZOMBIE;
482 ttyflush(tp, FREAD | FWRITE);
483 }
484
485 tp->t_oproc = 0; /* mark closed */
91447636 486
b0d623f7
A
487 tty_unlock(tp);
488
1c79356b
A
489 return (0);
490}
491
2d21ac55
A
492__private_extern__ int
493ptcread(dev_t dev, struct uio *uio, int flag)
1c79356b 494{
2d21ac55 495 struct tty *tp = pt_tty[minor(dev)];
1c79356b
A
496 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
497 char buf[BUFSIZ];
498 int error = 0, cc;
91447636 499
b0d623f7 500 tty_lock(tp);
1c79356b
A
501
502 /*
503 * We want to block until the slave
504 * is open, and there's something to read;
505 * but if we lost the slave or we're NBIO,
506 * then return the appropriate error instead.
507 */
508 for (;;) {
509 if (tp->t_state&TS_ISOPEN) {
510 if (pti->pt_flags&PF_PKT && pti->pt_send) {
511 error = ureadc((int)pti->pt_send, uio);
512 if (error)
91447636 513 goto out;
1c79356b 514 if (pti->pt_send & TIOCPKT_IOCTL) {
91447636 515 cc = min(uio_resid(uio),
1c79356b
A
516 sizeof(tp->t_termios));
517 uiomove((caddr_t)&tp->t_termios, cc,
518 uio);
519 }
520 pti->pt_send = 0;
91447636 521 goto out;
1c79356b
A
522 }
523 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
524 error = ureadc((int)pti->pt_ucntl, uio);
525 if (error)
91447636 526 goto out;
1c79356b 527 pti->pt_ucntl = 0;
91447636 528 goto out;
1c79356b
A
529 }
530 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
531 break;
532 }
533 if ((tp->t_state & TS_CONNECTED) == 0)
91447636
A
534 goto out; /* EOF */
535 if (flag & IO_NDELAY) {
536 error = EWOULDBLOCK;
537 goto out;
538 }
b0d623f7 539 error = ttysleep(tp, TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
1c79356b 540 if (error)
91447636 541 goto out;
1c79356b
A
542 }
543 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
544 error = ureadc(0, uio);
91447636 545 while (uio_resid(uio) > 0 && error == 0) {
2d21ac55 546 cc = q_to_b(&tp->t_outq, (u_char *)buf, min(uio_resid(uio), BUFSIZ));
1c79356b
A
547 if (cc <= 0)
548 break;
549 error = uiomove(buf, cc, uio);
550 }
91447636
A
551 (*linesw[tp->t_line].l_start)(tp);
552
553out:
b0d623f7
A
554 tty_unlock(tp);
555
1c79356b
A
556 return (error);
557}
558
b0d623f7
A
559/*
560 * Line discipline callback
561 *
562 * Locks: tty_lock() is assumed held on entry and exit.
563 */
2d21ac55
A
564__private_extern__ void
565ptsstop(struct tty *tp, int flush)
1c79356b 566{
b0d623f7 567 struct pt_ioctl *pti;
1c79356b 568 int flag;
91447636 569
b0d623f7 570 pti = &pt_ioctl[minor(tp->t_dev)];
1c79356b
A
571
572 /* note: FLUSHREAD and FLUSHWRITE already ok */
573 if (flush == 0) {
574 flush = TIOCPKT_STOP;
575 pti->pt_flags |= PF_STOPPED;
576 } else
577 pti->pt_flags &= ~PF_STOPPED;
578 pti->pt_send |= flush;
579 /* change of perspective */
580 flag = 0;
581 if (flush & FREAD)
582 flag |= FWRITE;
583 if (flush & FWRITE)
584 flag |= FREAD;
585 ptcwakeup(tp, flag);
586}
587
2d21ac55
A
588__private_extern__ int
589ptcselect(dev_t dev, int rw, void *wql, struct proc *p)
1c79356b 590{
2d21ac55 591 struct tty *tp = pt_tty[minor(dev)];
1c79356b 592 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
91447636 593 int retval = 0;
1c79356b 594
b0d623f7 595 tty_lock(tp);
91447636
A
596
597 if ((tp->t_state & TS_CONNECTED) == 0) {
598 retval = 1;
599 goto out;
600 }
1c79356b
A
601 switch (rw) {
602
603 case FREAD:
604 /*
605 * Need to block timeouts (ttrstart).
606 */
1c79356b
A
607 if ((tp->t_state&TS_ISOPEN) &&
608 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
91447636
A
609 retval = 1;
610 goto out;
1c79356b 611 }
1c79356b
A
612 /* FALLTHROUGH */
613
614 case 0: /* exceptional */
615 if ((tp->t_state&TS_ISOPEN) &&
616 ((pti->pt_flags&PF_PKT && pti->pt_send) ||
91447636
A
617 (pti->pt_flags&PF_UCNTL && pti->pt_ucntl))) {
618 retval = 1;
619 goto out;
620 }
0b4e3aa0 621 selrecord(p, &pti->pt_selr, wql);
1c79356b
A
622 break;
623
624
625 case FWRITE:
626 if (tp->t_state&TS_ISOPEN) {
627 if (pti->pt_flags & PF_REMOTE) {
91447636
A
628 if (tp->t_canq.c_cc == 0) {
629 retval = 1;
630 goto out;
631 }
1c79356b 632 } else {
91447636
A
633 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) {
634 retval = 1;
635 goto out;
636 }
2d21ac55 637 if (tp->t_canq.c_cc == 0 && (tp->t_lflag&ICANON)) {
91447636
A
638 retval = 1;
639 goto out;
640 }
1c79356b
A
641 }
642 }
0b4e3aa0 643 selrecord(p, &pti->pt_selw, wql);
1c79356b
A
644 break;
645
646 }
91447636 647out:
b0d623f7
A
648 tty_unlock(tp);
649
91447636 650 return (retval);
1c79356b
A
651}
652
2d21ac55
A
653__private_extern__ int
654ptcwrite(dev_t dev, struct uio *uio, int flag)
1c79356b 655{
2d21ac55
A
656 struct tty *tp = pt_tty[minor(dev)];
657 u_char *cp = NULL;
658 int cc = 0;
1c79356b 659 u_char locbuf[BUFSIZ];
91447636 660 int wcnt = 0;
1c79356b
A
661 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
662 int error = 0;
91447636 663
b0d623f7 664 tty_lock(tp);
1c79356b
A
665
666again:
667 if ((tp->t_state&TS_ISOPEN) == 0)
668 goto block;
669 if (pti->pt_flags & PF_REMOTE) {
670 if (tp->t_canq.c_cc)
671 goto block;
91447636 672 while ((uio_resid(uio) > 0 || cc > 0) &&
1c79356b
A
673 tp->t_canq.c_cc < TTYHOG - 1) {
674 if (cc == 0) {
91447636 675 cc = min(uio_resid(uio), BUFSIZ);
1c79356b
A
676 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
677 cp = locbuf;
678 error = uiomove((caddr_t)cp, cc, uio);
679 if (error)
91447636 680 goto out;
1c79356b
A
681 /* check again for safety */
682 if ((tp->t_state & TS_ISOPEN) == 0) {
683 /* adjust as usual */
91447636
A
684 uio_setresid(uio, (uio_resid(uio) + cc));
685 error = EIO;
686 goto out;
1c79356b
A
687 }
688 }
689 if (cc > 0) {
2d21ac55 690 cc = b_to_q((u_char *)cp, cc, &tp->t_canq);
1c79356b
A
691 /*
692 * XXX we don't guarantee that the canq size
693 * is >= TTYHOG, so the above b_to_q() may
694 * leave some bytes uncopied. However, space
695 * is guaranteed for the null terminator if
696 * we don't fail here since (TTYHOG - 1) is
697 * not a multiple of CBSIZE.
698 */
699 if (cc > 0)
700 break;
701 }
702 }
703 /* adjust for data copied in but not written */
91447636 704 uio_setresid(uio, (uio_resid(uio) + cc));
1c79356b
A
705 (void) putc(0, &tp->t_canq);
706 ttwakeup(tp);
707 wakeup(TSA_PTS_READ(tp));
91447636 708 goto out;
1c79356b 709 }
91447636 710 while (uio_resid(uio) > 0 || cc > 0) {
1c79356b 711 if (cc == 0) {
91447636 712 cc = min(uio_resid(uio), BUFSIZ);
1c79356b
A
713 cp = locbuf;
714 error = uiomove((caddr_t)cp, cc, uio);
715 if (error)
91447636 716 goto out;
1c79356b
A
717 /* check again for safety */
718 if ((tp->t_state & TS_ISOPEN) == 0) {
719 /* adjust for data copied in but not written */
91447636
A
720 uio_setresid(uio, (uio_resid(uio) + cc));
721 error = EIO;
722 goto out;
1c79356b
A
723 }
724 }
725 while (cc > 0) {
726 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
2d21ac55 727 (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
1c79356b
A
728 wakeup(TSA_HUP_OR_INPUT(tp));
729 goto block;
730 }
731 (*linesw[tp->t_line].l_rint)(*cp++, tp);
91447636 732 wcnt++;
1c79356b
A
733 cc--;
734 }
735 cc = 0;
736 }
91447636 737out:
b0d623f7
A
738 tty_unlock(tp);
739
91447636 740 return (error);
b0d623f7 741
1c79356b
A
742block:
743 /*
744 * Come here to wait for slave to open, for space
745 * in outq, or space in rawq, or an empty canq.
746 */
747 if ((tp->t_state & TS_CONNECTED) == 0) {
748 /* adjust for data copied in but not written */
91447636
A
749 uio_setresid(uio, (uio_resid(uio) + cc));
750 error = EIO;
751 goto out;
1c79356b
A
752 }
753 if (flag & IO_NDELAY) {
754 /* adjust for data copied in but not written */
91447636
A
755 uio_setresid(uio, (uio_resid(uio) + cc));
756 if (wcnt == 0)
757 error = EWOULDBLOCK;
758 goto out;
1c79356b 759 }
b0d623f7 760 error = ttysleep(tp, TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
1c79356b
A
761 if (error) {
762 /* adjust for data copied in but not written */
91447636
A
763 uio_setresid(uio, (uio_resid(uio) + cc));
764 goto out;
1c79356b
A
765 }
766 goto again;
767}
768
2d21ac55
A
769__private_extern__ int
770ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1c79356b 771{
2d21ac55
A
772 struct tty *tp = pt_tty[minor(dev)];
773 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
774 u_char *cc = tp->t_cc;
91447636 775 int stop, error = 0;
91447636 776
b0d623f7 777 tty_lock(tp);
1c79356b
A
778
779 /*
780 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
781 * ttywflush(tp) will hang if there are characters in the outq.
782 */
783 if (cmd == TIOCEXT) {
784 /*
785 * When the EXTPROC bit is being toggled, we need
786 * to send an TIOCPKT_IOCTL if the packet driver
787 * is turned on.
788 */
789 if (*(int *)data) {
790 if (pti->pt_flags & PF_PKT) {
791 pti->pt_send |= TIOCPKT_IOCTL;
792 ptcwakeup(tp, FREAD);
793 }
794 tp->t_lflag |= EXTPROC;
795 } else {
796 if ((tp->t_lflag & EXTPROC) &&
797 (pti->pt_flags & PF_PKT)) {
798 pti->pt_send |= TIOCPKT_IOCTL;
799 ptcwakeup(tp, FREAD);
800 }
801 tp->t_lflag &= ~EXTPROC;
802 }
91447636 803 goto out;
1c79356b 804 } else
1c79356b 805 if (cdevsw[major(dev)].d_open == ptcopen)
1c79356b
A
806 switch (cmd) {
807
808 case TIOCGPGRP:
809 /*
810 * We aviod calling ttioctl on the controller since,
811 * in that case, tp must be the controlling terminal.
812 */
813 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
91447636 814 goto out;
1c79356b
A
815
816 case TIOCPKT:
817 if (*(int *)data) {
91447636
A
818 if (pti->pt_flags & PF_UCNTL) {
819 error = EINVAL;
820 goto out;
821 }
1c79356b
A
822 pti->pt_flags |= PF_PKT;
823 } else
824 pti->pt_flags &= ~PF_PKT;
91447636 825 goto out;
1c79356b
A
826
827 case TIOCUCNTL:
828 if (*(int *)data) {
91447636
A
829 if (pti->pt_flags & PF_PKT) {
830 error = EINVAL;
831 goto out;
832 }
1c79356b
A
833 pti->pt_flags |= PF_UCNTL;
834 } else
835 pti->pt_flags &= ~PF_UCNTL;
91447636 836 goto out;
1c79356b
A
837
838 case TIOCREMOTE:
839 if (*(int *)data)
840 pti->pt_flags |= PF_REMOTE;
841 else
842 pti->pt_flags &= ~PF_REMOTE;
843 ttyflush(tp, FREAD|FWRITE);
91447636 844 goto out;
1c79356b 845
1c79356b
A
846 case TIOCSETP:
847 case TIOCSETN:
1c79356b 848 case TIOCSETD:
b0d623f7
A
849 case TIOCSETA_32:
850 case TIOCSETAW_32:
851 case TIOCSETAF_32:
852 case TIOCSETA_64:
853 case TIOCSETAW_64:
854 case TIOCSETAF_64:
1c79356b
A
855 ndflush(&tp->t_outq, tp->t_outq.c_cc);
856 break;
857
858 case TIOCSIG:
859 if (*(unsigned int *)data >= NSIG ||
91447636
A
860 *(unsigned int *)data == 0) {
861 error = EINVAL;
862 goto out;
863 }
1c79356b
A
864 if ((tp->t_lflag&NOFLSH) == 0)
865 ttyflush(tp, FREAD|FWRITE);
1c79356b
A
866 if ((*(unsigned int *)data == SIGINFO) &&
867 ((tp->t_lflag&NOKERNINFO) == 0))
b0d623f7
A
868 ttyinfo_locked(tp);
869 /*
870 * SAFE: All callers drop the lock on return and
871 * SAFE: the linesw[] will short circut this call
872 * SAFE: if the ioctl() is eaten before the lower
873 * SAFE: level code gets to see it.
874 */
875 tty_unlock(tp);
876 tty_pgsignal(tp, *(unsigned int *)data, 1);
877 tty_lock(tp);
91447636 878 goto out;
2d21ac55
A
879
880 case TIOCPTYGRANT: /* grantpt(3) */
881 /*
882 * Change the uid of the slave to that of the calling
883 * thread, change the gid of the slave to GID_TTY,
884 * change the mode to 0620 (rw--w----).
885 */
886 {
887 _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY);
888 goto out;
889 }
890
891 case TIOCPTYGNAME: /* ptsname(3) */
892 /*
893 * Report the name of the slave device in *data
894 * (128 bytes max.). Use the same derivation method
895 * used for calling devfs_make_node() to create it.
896 */
897 snprintf(data, 128, "/dev/tty%c%x",
898 START_CHAR + (minor(dev) / HEX_BASE),
899 minor(dev) % HEX_BASE);
900 error = 0;
901 goto out;
902
903 case TIOCPTYUNLK: /* unlockpt(3) */
904 /*
905 * Unlock the slave device so that it can be opened.
906 */
907 error = 0;
908 goto out;
1c79356b
A
909 }
910 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
91447636 911 if (error == ENOTTY) {
b0d623f7 912 error = ttioctl_locked(tp, cmd, data, flag, p);
2d21ac55
A
913 if (error == ENOTTY) {
914 if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) {
915 /* Process the UIOCMD ioctl group */
916 if (cmd & 0xff) {
917 pti->pt_ucntl = (u_char)cmd;
918 ptcwakeup(tp, FREAD);
919 }
920 error = 0;
921 goto out;
922 } else if (cmd == TIOCSBRK || cmd == TIOCCBRK) {
923 /*
924 * POSIX conformance; rdar://3936338
925 *
926 * Clear ENOTTY in the case of setting or
927 * clearing a break failing because pty's
928 * don't support break like real serial
929 * ports.
930 */
931 error = 0;
932 goto out;
1c79356b 933 }
1c79356b 934 }
1c79356b 935 }
91447636 936
1c79356b
A
937 /*
938 * If external processing and packet mode send ioctl packet.
939 */
940 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
941 switch(cmd) {
b0d623f7
A
942 case TIOCSETA_32:
943 case TIOCSETAW_32:
944 case TIOCSETAF_32:
945 case TIOCSETA_64:
946 case TIOCSETAW_64:
947 case TIOCSETAF_64:
1c79356b
A
948 case TIOCSETP:
949 case TIOCSETN:
1c79356b
A
950 case TIOCSETC:
951 case TIOCSLTC:
952 case TIOCLBIS:
953 case TIOCLBIC:
954 case TIOCLSET:
1c79356b
A
955 pti->pt_send |= TIOCPKT_IOCTL;
956 ptcwakeup(tp, FREAD);
957 default:
958 break;
959 }
960 }
961 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
962 && CCEQ(cc[VSTART], CTRL('q'));
963 if (pti->pt_flags & PF_NOSTOP) {
964 if (stop) {
965 pti->pt_send &= ~TIOCPKT_NOSTOP;
966 pti->pt_send |= TIOCPKT_DOSTOP;
967 pti->pt_flags &= ~PF_NOSTOP;
968 ptcwakeup(tp, FREAD);
969 }
970 } else {
971 if (!stop) {
972 pti->pt_send &= ~TIOCPKT_DOSTOP;
973 pti->pt_send |= TIOCPKT_NOSTOP;
974 pti->pt_flags |= PF_NOSTOP;
975 ptcwakeup(tp, FREAD);
976 }
977 }
91447636 978out:
b0d623f7
A
979 tty_unlock(tp);
980
1c79356b
A
981 return (error);
982}