X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/743b15655a24ee3fe9f458f383003e011db0558f..6d2010ae8f7a6078e10b361c6962983bab233e0f:/bsd/kern/tty_pty.c?ds=sidebyside diff --git a/bsd/kern/tty_pty.c b/bsd/kern/tty_pty.c index b396f4b09..8fb35c04a 100644 --- a/bsd/kern/tty_pty.c +++ b/bsd/kern/tty_pty.c @@ -1,25 +1,30 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1997-2006 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */ /* * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -69,17 +74,12 @@ #include #include #include -#include +#include #include #include #include #include -#ifndef NeXT - -#define FREE_BSDSTATIC static -#else -#define FREE_BSDSTATIC __private_extern__ #define d_devtotty_t struct tty ** #ifdef d_stop_t @@ -87,44 +87,27 @@ #endif typedef void d_stop_t(struct tty *tp, int rw); -#endif /* NeXT */ - /* XXX function should be removed??? */ int pty_init(int n_ptys); -#ifdef notyet -static void ptyattach(int n); -#endif +/* XXX should be a devfs function */ +int _devfs_setattr(void * handle, unsigned short mode, uid_t uid, gid_t gid); + static void ptsstart(struct tty *tp); static void ptcwakeup(struct tty *tp, int flag); -FREE_BSDSTATIC d_open_t ptsopen; -FREE_BSDSTATIC d_close_t ptsclose; -FREE_BSDSTATIC d_read_t ptsread; -FREE_BSDSTATIC d_write_t ptswrite; -FREE_BSDSTATIC d_ioctl_t ptyioctl; -FREE_BSDSTATIC d_stop_t ptsstop; -FREE_BSDSTATIC d_devtotty_t ptydevtotty; -FREE_BSDSTATIC d_open_t ptcopen; -FREE_BSDSTATIC d_close_t ptcclose; -FREE_BSDSTATIC d_read_t ptcread; -FREE_BSDSTATIC d_write_t ptcwrite; -FREE_BSDSTATIC d_select_t ptcselect; - -#ifndef NeXT -#define CDEV_MAJOR_S 5 -#define CDEV_MAJOR_C 6 -static struct cdevsw pts_cdevsw = - { ptsopen, ptsclose, ptsread, ptswrite, /*5*/ - ptyioctl, ptsstop, nullreset, ptydevtotty,/* ttyp */ - ttselect, nommap, NULL, "pts", NULL, -1 }; - -static struct cdevsw ptc_cdevsw = - { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/ - ptyioctl, nullstop, nullreset, ptydevtotty,/* ptyp */ - ptcselect, nommap, NULL, "ptc", NULL, -1 }; -#endif /* !NeXT */ - +__private_extern__ d_open_t ptsopen; +__private_extern__ d_close_t ptsclose; +__private_extern__ d_read_t ptsread; +__private_extern__ d_write_t ptswrite; +__private_extern__ d_ioctl_t ptyioctl; +__private_extern__ d_stop_t ptsstop; +__private_extern__ d_devtotty_t ptydevtotty; +__private_extern__ d_open_t ptcopen; +__private_extern__ d_close_t ptcclose; +__private_extern__ d_read_t ptcread; +__private_extern__ d_write_t ptcwrite; +__private_extern__ d_select_t ptcselect; #if NPTY == 1 #undef NPTY @@ -132,38 +115,21 @@ static struct cdevsw ptc_cdevsw = #warning You have only one pty defined, redefining to 32. #endif -#ifndef NeXT -#ifdef DEVFS -#define MAXUNITS (8 * 32) -static void *devfs_token_pts[MAXUNITS]; -static void *devfs_token_ptc[MAXUNITS]; -static const char jnames[] = "pqrsPQRS"; -#if NPTY > MAXUNITS -#undef NPTY -#define NPTY MAXUNITS -#warning Can't have more than 256 pty's with DEVFS defined. -#endif /* NPTY > MAXUNITS */ -#endif /* DEVFS */ -#endif /* !NeXT */ - #define BUFSIZ 100 /* Chunk size iomoved to/from user */ /* * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] */ -#ifndef NeXT -FREE_BSDSTATIC struct tty pt_tty[NPTY]; /* XXX */ -#else /* NeXT */ -/* NeXT All references to have been changed to indirections in the file */ -FREE_BSDSTATIC struct tty *pt_tty[NPTY] = { NULL }; -#endif /* ! NeXT */ +/* All references to have been changed to indirections in the file */ +__private_extern__ struct tty *pt_tty[NPTY] = { NULL }; static struct pt_ioctl { int pt_flags; struct selinfo pt_selr, pt_selw; u_char pt_send; u_char pt_ucntl; + void *pt_devhandle; /* slave device handle for grantpt() */ } pt_ioctl[NPTY]; /* XXX */ static int npty = NPTY; /* for pstat -t */ @@ -173,38 +139,6 @@ static int npty = NPTY; /* for pstat -t */ #define PF_NOSTOP 0x40 #define PF_UCNTL 0x80 /* user control mode */ -#ifdef notyet -/* - * Establish n (or default if n is 1) ptys in the system. - * - * XXX cdevsw & pstat require the array `pty[]' to be an array - */ -FREEBSD_STATIC void -ptyattach(n) - int n; -{ - char *mem; - register u_long ntb; -#define DEFAULT_NPTY 32 - - /* maybe should allow 0 => none? */ - if (n <= 1) - n = DEFAULT_NPTY; - ntb = n * sizeof(struct tty); -#ifndef NeXT - mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl), - M_DEVBUF, M_WAITOK); -#else - MALLOC(mem, char *, ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl), - M_DEVBUF, M_WAITOK); -#endif /* !NeXT */ - pt_tty = (struct tty *)mem; - mem = (char *)ALIGN(mem + ntb); - pt_ioctl = (struct pt_ioctl *)mem; - npty = n; -} -#endif - #ifndef DEVFS int pty_init(__unused int n_ptys) @@ -227,7 +161,7 @@ pty_init(int n_ptys) int m = j * HEX_BASE + i; if (m == n_ptys) goto done; - (void)devfs_make_node(makedev(4, m), + pt_ioctl[m].pt_devhandle = devfs_make_node(makedev(4, m), DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, "tty%c%x", j + START_CHAR, i); (void)devfs_make_node(makedev(5, m), @@ -240,33 +174,36 @@ pty_init(int n_ptys) } #endif /* DEVFS */ -/*ARGSUSED*/ -FREE_BSDSTATIC int +__private_extern__ int ptsopen(dev_t dev, int flag, __unused int devtype, __unused struct proc *p) { - register struct tty *tp; + struct tty *tp; int error; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); -#ifndef NeXT - tp = &pt_tty[minor(dev)]; -#else /* * You will see this sort of code coming up in diffs later both * the ttymalloc and the tp indirection. */ if (minor(dev) >= npty) { error = ENXIO; - goto out; + goto err; } if (!pt_tty[minor(dev)]) { - tp = pt_tty[minor(dev)] = ttymalloc(); + /* + * If we can't allocate a new one, act as if we had run out + * of device nodes. + */ + if ((tp = pt_tty[minor(dev)] = ttymalloc()) == NULL) { + error = ENXIO; + goto err; + } } else tp = pt_tty[minor(dev)]; -#endif + + tty_lock(tp); + if ((tp->t_state & TS_ISOPEN) == 0) { - ttychars(tp); /* Set up default chars */ + termioschars(&tp->t_termios); /* Set up default chars */ tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; @@ -290,48 +227,56 @@ ptsopen(dev_t dev, int flag, __unused int devtype, __unused struct proc *p) error = (*linesw[tp->t_line].l_open)(dev, tp); if (error == 0) ptcwakeup(tp, FREAD|FWRITE); + out: - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); +err: return (error); } -FREE_BSDSTATIC int +__private_extern__ int ptsclose(dev_t dev, int flag, __unused int mode, __unused proc_t p) { - register struct tty *tp; + struct tty *tp; int err; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + /* + * This is temporary until the VSX conformance tests + * are fixed. They are hanging with a deadlock + * where close(pts) will not complete without t_timeout set + */ +#define FIX_VSX_HANG 1 +#ifdef FIX_VSX_HANG + int save_timeout; +#endif tp = pt_tty[minor(dev)]; + tty_lock(tp); +#ifdef FIX_VSX_HANG + save_timeout = tp->t_timeout; + tp->t_timeout = 60; +#endif err = (*linesw[tp->t_line].l_close)(tp, flag); ptsstop(tp, FREAD|FWRITE); (void) ttyclose(tp); - - (void) thread_funnel_set(kernel_flock, funnel_state); +#ifdef FIX_VSX_HANG + tp->t_timeout = save_timeout; +#endif + tty_unlock(tp); return (err); } -FREE_BSDSTATIC int -ptsread(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; +__private_extern__ int +ptsread(dev_t dev, struct uio *uio, int flag) { -#ifndef NeXT - struct proc *p = curproc; -#else struct proc *p = current_proc(); -#endif /* NeXT */ - register struct tty *tp = pt_tty[minor(dev)]; - register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + struct tty *tp = pt_tty[minor(dev)]; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; int error = 0; struct uthread *ut; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); + struct pgrp *pg; + tty_lock(tp); ut = (struct uthread *)get_bsdthread_info(current_thread()); again: @@ -339,20 +284,42 @@ again: while (isbackground(p, tp)) { if ((p->p_sigignore & sigmask(SIGTTIN)) || (ut->uu_sigmask & sigmask(SIGTTIN)) || - p->p_pgrp->pg_jobc == 0 || - p->p_flag & P_PPWAIT) { + p->p_lflag & P_LPPWAIT) { + error = EIO; + goto out; + } + + + pg = proc_pgrp(p); + if (pg == PGRP_NULL) { error = EIO; goto out; } - pgsignal(p->p_pgrp, SIGTTIN, 1); + /* + * SAFE: We about to drop the lock ourselves by + * SAFE: erroring out or sleeping anyway. + */ + tty_unlock(tp); + if (pg->pg_jobc == 0) { + pg_rele(pg); + tty_lock(tp); + error = EIO; + goto out; + } + pgsignal(pg, SIGTTIN, 1); + pg_rele(pg); + tty_lock(tp); + error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ptsbg", 0); if (error) goto out; } if (tp->t_canq.c_cc == 0) { - if (flag & IO_NDELAY) - return (EWOULDBLOCK); + if (flag & IO_NDELAY) { + error = EWOULDBLOCK; + goto out; + } error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH, "ptsin", 0); if (error) @@ -366,7 +333,7 @@ again: cc = min(uio_resid(uio), BUFSIZ); // Don't copy the very last byte cc = min(cc, tp->t_canq.c_cc - 1); - cc = q_to_b(&tp->t_canq, buf, cc); + cc = q_to_b(&tp->t_canq, (u_char *)buf, cc); error = uiomove(buf, cc, uio); if (error) break; @@ -380,7 +347,7 @@ again: error = (*linesw[tp->t_line].l_read)(tp, uio, flag); ptcwakeup(tp, FWRITE); out: - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); return (error); } @@ -389,40 +356,38 @@ out: * Wakeups of controlling tty will happen * indirectly, when tty driver calls ptsstart. */ -FREE_BSDSTATIC int -ptswrite(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; +__private_extern__ int +ptswrite(dev_t dev, struct uio *uio, int flag) { - register struct tty *tp; + struct tty *tp; int error; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); tp = pt_tty[minor(dev)]; + + tty_lock(tp); + if (tp->t_oproc == 0) error = EIO; else error = (*linesw[tp->t_line].l_write)(tp, uio, flag); - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); + return (error); } /* * Start output on pseudo-tty. * Wake up process selecting or sleeping for input from controlling tty. + * + * t_oproc for this driver; called from within the line discipline + * + * Locks: Assumes tp is locked on entry, remains locked on exit */ static void -ptsstart(tp) - struct tty *tp; +ptsstart(struct tty *tp) { - register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); + struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; if (tp->t_state & TS_TTSTOP) goto out; @@ -432,19 +397,16 @@ ptsstart(tp) } ptcwakeup(tp, FREAD); out: - (void) thread_funnel_set(kernel_flock, funnel_state); return; } +/* + * Locks: Assumes tty_lock() is held over this call. + */ static void -ptcwakeup(tp, flag) - struct tty *tp; - int flag; +ptcwakeup(struct tty *tp, int flag) { struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); if (flag & FREAD) { selwakeup(&pti->pt_selr); @@ -454,18 +416,14 @@ ptcwakeup(tp, flag) selwakeup(&pti->pt_selw); wakeup(TSA_PTC_WRITE(tp)); } - (void) thread_funnel_set(kernel_flock, funnel_state); } -FREE_BSDSTATIC int +__private_extern__ int ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p) { - register struct tty *tp; + struct tty *tp; struct pt_ioctl *pti; int error = 0; - boolean_t funnel_state; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); if (minor(dev) >= npty) { error = ENXIO; @@ -475,35 +433,39 @@ ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p) tp = pt_tty[minor(dev)] = ttymalloc(); } else tp = pt_tty[minor(dev)]; - if (tp->t_oproc) { - error = EIO; - goto out; - } - tp->t_oproc = ptsstart; - CLR(tp->t_state, TS_ZOMBIE); + + tty_lock(tp); + + /* If master is open OR slave is still draining, pty is still busy */ + if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) { + error = EBUSY; + } else { + tp->t_oproc = ptsstart; + CLR(tp->t_state, TS_ZOMBIE); #ifdef sun4c - tp->t_stop = ptsstop; + tp->t_stop = ptsstop; #endif - (void)(*linesw[tp->t_line].l_modem)(tp, 1); - tp->t_lflag &= ~EXTPROC; - pti = &pt_ioctl[minor(dev)]; - pti->pt_flags = 0; - pti->pt_send = 0; - pti->pt_ucntl = 0; + (void)(*linesw[tp->t_line].l_modem)(tp, 1); + tp->t_lflag &= ~EXTPROC; + pti = &pt_ioctl[minor(dev)]; + pti->pt_flags = 0; + pti->pt_send = 0; + pti->pt_ucntl = 0; + } + + tty_unlock(tp); + out: - (void) thread_funnel_set(kernel_flock, funnel_state); return (error); } -FREE_BSDSTATIC int +__private_extern__ int ptcclose(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p) { - register struct tty *tp; - boolean_t funnel_state; + struct tty *tp = pt_tty[minor(dev)]; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + tty_lock(tp); - tp = pt_tty[minor(dev)]; (void)(*linesw[tp->t_line].l_modem)(tp, 0); /* @@ -522,23 +484,20 @@ ptcclose(dev_t dev, __unused int flags, __unused int fmt, __unused proc_t p) tp->t_oproc = 0; /* mark closed */ - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); + return (0); } -FREE_BSDSTATIC int -ptcread(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; +__private_extern__ int +ptcread(dev_t dev, struct uio *uio, int flag) { - register struct tty *tp = pt_tty[minor(dev)]; + struct tty *tp = pt_tty[minor(dev)]; struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; char buf[BUFSIZ]; int error = 0, cc; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + tty_lock(tp); /* * We want to block until the slave @@ -577,14 +536,14 @@ ptcread(dev, uio, flag) error = EWOULDBLOCK; goto out; } - error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); + error = ttysleep(tp, TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); if (error) goto out; } if (pti->pt_flags & (PF_PKT|PF_UCNTL)) error = ureadc(0, uio); while (uio_resid(uio) > 0 && error == 0) { - cc = q_to_b(&tp->t_outq, buf, min(uio_resid(uio), BUFSIZ)); + cc = q_to_b(&tp->t_outq, (u_char *)buf, min(uio_resid(uio), BUFSIZ)); if (cc <= 0) break; error = uiomove(buf, cc, uio); @@ -592,20 +551,23 @@ ptcread(dev, uio, flag) (*linesw[tp->t_line].l_start)(tp); out: - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); + return (error); } -FREE_BSDSTATIC void -ptsstop(tp, flush) - register struct tty *tp; - int flush; +/* + * Line discipline callback + * + * Locks: tty_lock() is assumed held on entry and exit. + */ +__private_extern__ void +ptsstop(struct tty *tp, int flush) { - struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + struct pt_ioctl *pti; int flag; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + pti = &pt_ioctl[minor(tp->t_dev)]; /* note: FLUSHREAD and FLUSHWRITE already ok */ if (flush == 0) { @@ -621,23 +583,16 @@ ptsstop(tp, flush) if (flush & FWRITE) flag |= FREAD; ptcwakeup(tp, flag); - - (void) thread_funnel_set(kernel_flock, funnel_state); } -FREE_BSDSTATIC int -ptcselect(dev, rw, wql, p) - dev_t dev; - int rw; - void * wql; - struct proc *p; +__private_extern__ int +ptcselect(dev_t dev, int rw, void *wql, struct proc *p) { - register struct tty *tp = pt_tty[minor(dev)]; + struct tty *tp = pt_tty[minor(dev)]; struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; int retval = 0; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + tty_lock(tp); if ((tp->t_state & TS_CONNECTED) == 0) { retval = 1; @@ -679,7 +634,7 @@ ptcselect(dev, rw, wql, p) retval = 1; goto out; } - if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) { + if (tp->t_canq.c_cc == 0 && (tp->t_lflag&ICANON)) { retval = 1; goto out; } @@ -690,26 +645,23 @@ ptcselect(dev, rw, wql, p) } out: - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); + return (retval); } -FREE_BSDSTATIC int -ptcwrite(dev, uio, flag) - dev_t dev; - register struct uio *uio; - int flag; +__private_extern__ int +ptcwrite(dev_t dev, struct uio *uio, int flag) { - register struct tty *tp = pt_tty[minor(dev)]; - register u_char *cp = NULL; - register int cc = 0; + struct tty *tp = pt_tty[minor(dev)]; + u_char *cp = NULL; + int cc = 0; u_char locbuf[BUFSIZ]; int wcnt = 0; struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; int error = 0; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + tty_lock(tp); again: if ((tp->t_state&TS_ISOPEN) == 0) @@ -735,7 +687,7 @@ again: } } if (cc > 0) { - cc = b_to_q((char *)cp, cc, &tp->t_canq); + cc = b_to_q((u_char *)cp, cc, &tp->t_canq); /* * XXX we don't guarantee that the canq size * is >= TTYHOG, so the above b_to_q() may @@ -772,7 +724,7 @@ again: } while (cc > 0) { if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && - (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { + (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { wakeup(TSA_HUP_OR_INPUT(tp)); goto block; } @@ -783,8 +735,10 @@ again: cc = 0; } out: - (void) thread_funnel_set(kernel_flock, funnel_state); + tty_unlock(tp); + return (error); + block: /* * Come here to wait for slave to open, for space @@ -803,7 +757,7 @@ block: error = EWOULDBLOCK; goto out; } - error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); + error = ttysleep(tp, TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); if (error) { /* adjust for data copied in but not written */ uio_setresid(uio, (uio_resid(uio) + cc)); @@ -812,44 +766,15 @@ block: goto again; } -#ifndef NeXT -/* XXX we eventually want to go to this model, - * but premier can't change the cdevsw */ -static struct tty * -ptydevtotty(dev) - dev_t dev; -{ - if (minor(dev) >= npty) - return (NULL); - - return &pt_tty[minor(dev)]; -} -#endif /* !NeXT */ - -/*ARGSUSED*/ -FREE_BSDSTATIC int -#ifndef NeXT -ptyioctl(dev, cmd, data, flag) - dev_t dev; - int cmd; - caddr_t data; - int flag; -#else -ptyioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -#endif +__private_extern__ int +ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { - register struct tty *tp = pt_tty[minor(dev)]; - register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; - register u_char *cc = tp->t_cc; + struct tty *tp = pt_tty[minor(dev)]; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + u_char *cc = tp->t_cc; int stop, error = 0; - boolean_t funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + tty_lock(tp); /* * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. @@ -877,11 +802,7 @@ ptyioctl(dev, cmd, data, flag, p) } goto out; } else -#ifndef NeXT - if (cdevsw[major(dev)]->d_open == ptcopen) -#else if (cdevsw[major(dev)].d_open == ptcopen) -#endif switch (cmd) { case TIOCGPGRP: @@ -922,14 +843,15 @@ ptyioctl(dev, cmd, data, flag, p) ttyflush(tp, FREAD|FWRITE); goto out; -#if COMPAT_43_TTY case TIOCSETP: case TIOCSETN: -#endif case TIOCSETD: - case TIOCSETA: - case TIOCSETAW: - case TIOCSETAF: + case TIOCSETA_32: + case TIOCSETAW_32: + case TIOCSETAF_32: + case TIOCSETA_64: + case TIOCSETAW_64: + case TIOCSETAF_64: ndflush(&tp->t_outq, tp->t_outq.c_cc); break; @@ -941,24 +863,74 @@ ptyioctl(dev, cmd, data, flag, p) } if ((tp->t_lflag&NOFLSH) == 0) ttyflush(tp, FREAD|FWRITE); - pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); if ((*(unsigned int *)data == SIGINFO) && ((tp->t_lflag&NOKERNINFO) == 0)) - ttyinfo(tp); + ttyinfo_locked(tp); + /* + * SAFE: All callers drop the lock on return and + * SAFE: the linesw[] will short circut this call + * SAFE: if the ioctl() is eaten before the lower + * SAFE: level code gets to see it. + */ + tty_unlock(tp); + tty_pgsignal(tp, *(unsigned int *)data, 1); + tty_lock(tp); + goto out; + + case TIOCPTYGRANT: /* grantpt(3) */ + /* + * Change the uid of the slave to that of the calling + * thread, change the gid of the slave to GID_TTY, + * change the mode to 0620 (rw--w----). + */ + { + _devfs_setattr(pti->pt_devhandle, 0620, kauth_getuid(), GID_TTY); + goto out; + } + + case TIOCPTYGNAME: /* ptsname(3) */ + /* + * Report the name of the slave device in *data + * (128 bytes max.). Use the same derivation method + * used for calling devfs_make_node() to create it. + */ + snprintf(data, 128, "/dev/tty%c%x", + START_CHAR + (minor(dev) / HEX_BASE), + minor(dev) % HEX_BASE); + error = 0; + goto out; + + case TIOCPTYUNLK: /* unlockpt(3) */ + /* + * Unlock the slave device so that it can be opened. + */ + error = 0; goto out; } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error == ENOTTY) { - error = ttioctl(tp, cmd, data, flag, p); - if (error == ENOTTY - && pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) { - /* Process the UIOCMD ioctl group */ - if (cmd & 0xff) { - pti->pt_ucntl = (u_char)cmd; - ptcwakeup(tp, FREAD); + error = ttioctl_locked(tp, cmd, data, flag, p); + if (error == ENOTTY) { + if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) { + /* Process the UIOCMD ioctl group */ + if (cmd & 0xff) { + pti->pt_ucntl = (u_char)cmd; + ptcwakeup(tp, FREAD); + } + error = 0; + goto out; + } else if (cmd == TIOCSBRK || cmd == TIOCCBRK) { + /* + * POSIX conformance; rdar://3936338 + * + * Clear ENOTTY in the case of setting or + * clearing a break failing because pty's + * don't support break like real serial + * ports. + */ + error = 0; + goto out; } - error = 0; - goto out; } } @@ -967,20 +939,19 @@ ptyioctl(dev, cmd, data, flag, p) */ if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { switch(cmd) { - case TIOCSETA: - case TIOCSETAW: - case TIOCSETAF: -#if COMPAT_43_TTY + case TIOCSETA_32: + case TIOCSETAW_32: + case TIOCSETAF_32: + case TIOCSETA_64: + case TIOCSETAW_64: + case TIOCSETAF_64: case TIOCSETP: case TIOCSETN: -#endif -#if COMPAT_43_TTY || defined(COMPAT_SUNOS) case TIOCSETC: case TIOCSLTC: case TIOCLBIS: case TIOCLBIC: case TIOCLSET: -#endif pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); default: @@ -1005,43 +976,7 @@ ptyioctl(dev, cmd, data, flag, p) } } out: - (void) thread_funnel_set(kernel_flock, funnel_state); - return (error); -} + tty_unlock(tp); -#ifndef NeXT -static ptc_devsw_installed = 0; - -static void -ptc_drvinit(void *unused) -{ -#ifdef DEVFS - int i,j,k; -#endif - dev_t dev; - - if( ! ptc_devsw_installed ) { - dev = makedev(CDEV_MAJOR_S, 0); - cdevsw_add(&dev, &pts_cdevsw, NULL); - dev = makedev(CDEV_MAJOR_C, 0); - cdevsw_add(&dev, &ptc_cdevsw, NULL); - ptc_devsw_installed = 1; -#ifdef DEVFS - for ( i = 0 ; i