pty.c revision 147982
1139804Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 4. Neither the name of the University nor the names of its contributors
141541Srgrimes *    may be used to endorse or promote products derived from this software
151541Srgrimes *    without specific prior written permission.
161541Srgrimes *
171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271541Srgrimes * SUCH DAMAGE.
281541Srgrimes *
2914511Shsu *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
301541Srgrimes */
311541Srgrimes
32116182Sobrien#include <sys/cdefs.h>
33116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/tty_pty.c 147982 2005-07-14 10:22:09Z rwatson $");
34116182Sobrien
351541Srgrimes/*
361541Srgrimes * Pseudo-teletype Driver
371541Srgrimes * (Actually two drivers, requiring two entries in 'cdevsw')
381541Srgrimes */
3931778Seivind#include "opt_compat.h"
40111899Sdas#include "opt_tty.h"
411541Srgrimes#include <sys/param.h>
421541Srgrimes#include <sys/systm.h>
4391140Stanimura#include <sys/lock.h>
4491140Stanimura#include <sys/mutex.h>
4591140Stanimura#include <sys/sx.h>
46130892Sphk#ifndef BURN_BRIDGES
47130344Sphk#if defined(COMPAT_43)
4824207Sbde#include <sys/ioctl_compat.h>
4924207Sbde#endif
50130892Sphk#endif
511541Srgrimes#include <sys/proc.h>
521541Srgrimes#include <sys/tty.h>
531541Srgrimes#include <sys/conf.h>
5424131Sbde#include <sys/fcntl.h>
5529354Speter#include <sys/poll.h>
561541Srgrimes#include <sys/kernel.h>
57139205Sphk#include <sys/uio.h>
583308Sphk#include <sys/signalvar.h>
5949536Sphk#include <sys/malloc.h>
601541Srgrimes
6169774Sphkstatic MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
6212517Sjulian
6392723Salfredstatic void ptsstart(struct tty *tp);
6492723Salfredstatic void ptsstop(struct tty *tp, int rw);
6592723Salfredstatic void ptcwakeup(struct tty *tp, int flag);
66147982Srwatsonstatic struct cdev *ptyinit(struct cdev *cdev, struct thread *td);
6711789Sbde
6812675Sjulianstatic	d_open_t	ptsopen;
6912675Sjulianstatic	d_close_t	ptsclose;
7012675Sjulianstatic	d_read_t	ptsread;
7112675Sjulianstatic	d_write_t	ptswrite;
72135622Sphkstatic	d_ioctl_t	ptsioctl;
7312675Sjulianstatic	d_open_t	ptcopen;
7412675Sjulianstatic	d_close_t	ptcclose;
7512675Sjulianstatic	d_read_t	ptcread;
76135622Sphkstatic	d_ioctl_t	ptcioctl;
7712675Sjulianstatic	d_write_t	ptcwrite;
7829354Speterstatic	d_poll_t	ptcpoll;
7912675Sjulian
8047625Sphkstatic struct cdevsw pts_cdevsw = {
81126080Sphk	.d_version =	D_VERSION,
82111815Sphk	.d_open =	ptsopen,
83111815Sphk	.d_close =	ptsclose,
84111815Sphk	.d_read =	ptsread,
85111815Sphk	.d_write =	ptswrite,
86135622Sphk	.d_ioctl =	ptsioctl,
87111815Sphk	.d_name =	"pts",
88126080Sphk	.d_flags =	D_TTY | D_NEEDGIANT,
8938485Sbde};
9012675Sjulian
9147625Sphkstatic struct cdevsw ptc_cdevsw = {
92126080Sphk	.d_version =	D_VERSION,
93111815Sphk	.d_open =	ptcopen,
94111815Sphk	.d_close =	ptcclose,
95111815Sphk	.d_read =	ptcread,
96111815Sphk	.d_write =	ptcwrite,
97135622Sphk	.d_ioctl =	ptcioctl,
98111815Sphk	.d_poll =	ptcpoll,
99111815Sphk	.d_name =	"ptc",
100126080Sphk	.d_flags =	D_TTY | D_NEEDGIANT,
10138485Sbde};
10212675Sjulian
1031541Srgrimes#define BUFSIZ 100		/* Chunk size iomoved to/from user */
1041541Srgrimes
105130263Sphkstruct	ptsc {
1061541Srgrimes	int	pt_flags;
1071541Srgrimes	struct	selinfo pt_selr, pt_selw;
1081541Srgrimes	u_char	pt_send;
1091541Srgrimes	u_char	pt_ucntl;
110130054Sphk	struct tty *pt_tty;
111130585Sphk	struct cdev *devs, *devc;
11257070Srwatson	struct	prison *pt_prison;
11349536Sphk};
1141541Srgrimes
1151541Srgrimes#define	PF_PKT		0x08		/* packet mode */
1161541Srgrimes#define	PF_STOPPED	0x10		/* user told stopped */
1171541Srgrimes#define	PF_NOSTOP	0x40
1181541Srgrimes#define PF_UCNTL	0x80		/* user control mode */
1191541Srgrimes
120130259Sphk#define	TSA_PTC_READ(tp)	((void *)&(tp)->t_outq.c_cf)
121130259Sphk#define	TSA_PTC_WRITE(tp)	((void *)&(tp)->t_rawq.c_cl)
122130259Sphk#define	TSA_PTS_READ(tp)	((void *)&(tp)->t_canq)
123130259Sphk
12477176Sphkstatic char *names = "pqrsPQRS";
1251541Srgrimes/*
12649536Sphk * This function creates and initializes a pts/ptc pair
1271541Srgrimes *
12849536Sphk * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
12949536Sphk * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
13049536Sphk *
131111742Sdes * XXX: define and add mapping of upper minor bits to allow more
13249536Sphk *      than 256 ptys.
1331541Srgrimes */
134130585Sphkstatic struct cdev *
135147982Srwatsonptyinit(struct cdev *devc, struct thread *td)
1361541Srgrimes{
137130585Sphk	struct cdev *devs;
138130263Sphk	struct ptsc *pt;
13977176Sphk	int n;
1401541Srgrimes
14177176Sphk	n = minor(devc);
14249536Sphk	/* For now we only map the lower 8 bits of the minor */
14349536Sphk	if (n & ~0xff)
144130640Sphk		return (NULL);
14549536Sphk
14678405Sbrian	devc->si_flags &= ~SI_CHEAPCLONE;
14778405Sbrian
148111119Simp	pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
149147982Srwatson	pt->devs = devs = make_dev_cred(&pts_cdevsw, n, td->td_ucred,
15066067Sphk	    UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32);
15177176Sphk	pt->devc = devc;
15249536Sphk
153130054Sphk	pt->pt_tty = ttymalloc(pt->pt_tty);
154135298Sphk	pt->pt_tty->t_sc = pt;
15549536Sphk	devs->si_drv1 = devc->si_drv1 = pt;
156130054Sphk	devs->si_tty = devc->si_tty = pt->pt_tty;
157130054Sphk	pt->pt_tty->t_dev = devs;
15864880Sphk	return (devc);
15916322Sgpalmer}
1601541Srgrimes
1611541Srgrimes/*ARGSUSED*/
16212675Sjulianstatic	int
163130585Sphkptsopen(struct cdev *dev, int flag, int devtype, struct thread *td)
1641541Srgrimes{
165111742Sdes	struct tty *tp;
1661541Srgrimes	int error;
167130263Sphk	struct ptsc *pt;
1681541Srgrimes
16949536Sphk	if (!dev->si_drv1)
170111742Sdes		return(ENXIO);
171130263Sphk	pt = dev->si_drv1;
17250652Sphk	tp = dev->si_tty;
1731541Srgrimes	if ((tp->t_state & TS_ISOPEN) == 0) {
174136680Sphk		ttyinitmode(tp, 1, 0);
175125839Srwatson	} else if (tp->t_state & TS_XCLUDE && suser(td))
1761541Srgrimes		return (EBUSY);
177130263Sphk	else if (pt->pt_prison != td->td_ucred->cr_prison)
17857070Srwatson		return (EBUSY);
1791541Srgrimes	if (tp->t_oproc)			/* Ctrlr still around. */
180130077Sphk		(void)ttyld_modem(tp, 1);
1811541Srgrimes	while ((tp->t_state & TS_CARR_ON) == 0) {
1821541Srgrimes		if (flag&FNONBLOCK)
1831541Srgrimes			break;
1849639Sbde		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
1859624Sbde				 "ptsopn", 0);
1863308Sphk		if (error)
1871541Srgrimes			return (error);
1881541Srgrimes	}
189130077Sphk	error = ttyld_open(tp, dev);
1907724Sache	if (error == 0)
1917724Sache		ptcwakeup(tp, FREAD|FWRITE);
1921541Srgrimes	return (error);
1931541Srgrimes}
1941541Srgrimes
19512675Sjulianstatic	int
196130585Sphkptsclose(struct cdev *dev, int flag, int mode, struct thread *td)
1971541Srgrimes{
198111742Sdes	struct tty *tp;
1991541Srgrimes	int err;
2001541Srgrimes
20150652Sphk	tp = dev->si_tty;
202130077Sphk	err = ttyld_close(tp, flag);
203132226Sphk	(void) tty_close(tp);
2041541Srgrimes	return (err);
2051541Srgrimes}
2061541Srgrimes
20712675Sjulianstatic	int
208130585Sphkptsread(struct cdev *dev, struct uio *uio, int flag)
2091541Srgrimes{
210111742Sdes	struct tty *tp = dev->si_tty;
2111541Srgrimes	int error = 0;
2121541Srgrimes
213131114Sphk	if (tp->t_oproc)
214131114Sphk		error = ttyld_read(tp, uio, flag);
2151541Srgrimes	ptcwakeup(tp, FWRITE);
2161541Srgrimes	return (error);
2171541Srgrimes}
2181541Srgrimes
2191541Srgrimes/*
2201541Srgrimes * Write to pseudo-tty.
2211541Srgrimes * Wakeups of controlling tty will happen
2221541Srgrimes * indirectly, when tty driver calls ptsstart.
2231541Srgrimes */
22412675Sjulianstatic	int
225130585Sphkptswrite(struct cdev *dev, struct uio *uio, int flag)
2261541Srgrimes{
227111742Sdes	struct tty *tp;
2281541Srgrimes
22950652Sphk	tp = dev->si_tty;
2301541Srgrimes	if (tp->t_oproc == 0)
2311541Srgrimes		return (EIO);
232130077Sphk	return (ttyld_write(tp, uio, flag));
2331541Srgrimes}
2341541Srgrimes
2351541Srgrimes/*
2361541Srgrimes * Start output on pseudo-tty.
2371541Srgrimes * Wake up process selecting or sleeping for input from controlling tty.
2381541Srgrimes */
23912819Sphkstatic void
240130262Sphkptsstart(struct tty *tp)
2411541Srgrimes{
242135298Sphk	struct ptsc *pt = tp->t_sc;
2431541Srgrimes
2441541Srgrimes	if (tp->t_state & TS_TTSTOP)
2451541Srgrimes		return;
246130263Sphk	if (pt->pt_flags & PF_STOPPED) {
247130263Sphk		pt->pt_flags &= ~PF_STOPPED;
248130263Sphk		pt->pt_send = TIOCPKT_START;
2491541Srgrimes	}
2501541Srgrimes	ptcwakeup(tp, FREAD);
2511541Srgrimes}
2521541Srgrimes
25312819Sphkstatic void
254130262Sphkptcwakeup(struct tty *tp, int flag)
2551541Srgrimes{
256135298Sphk	struct ptsc *pt = tp->t_sc;
2571541Srgrimes
2581541Srgrimes	if (flag & FREAD) {
259130263Sphk		selwakeuppri(&pt->pt_selr, TTIPRI);
2609639Sbde		wakeup(TSA_PTC_READ(tp));
2611541Srgrimes	}
2621541Srgrimes	if (flag & FWRITE) {
263130263Sphk		selwakeuppri(&pt->pt_selw, TTOPRI);
2649639Sbde		wakeup(TSA_PTC_WRITE(tp));
2651541Srgrimes	}
2661541Srgrimes}
2671541Srgrimes
26812675Sjulianstatic	int
269130585Sphkptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
2701541Srgrimes{
271111742Sdes	struct tty *tp;
272130263Sphk	struct ptsc *pt;
2731541Srgrimes
27449536Sphk	if (!dev->si_drv1)
275147982Srwatson		ptyinit(dev, td);
27649536Sphk	if (!dev->si_drv1)
277111742Sdes		return(ENXIO);
27850652Sphk	tp = dev->si_tty;
2791541Srgrimes	if (tp->t_oproc)
2801541Srgrimes		return (EIO);
28159818Sache	tp->t_timeout = -1;
2821541Srgrimes	tp->t_oproc = ptsstart;
28351654Sphk	tp->t_stop = ptsstop;
284130077Sphk	(void)ttyld_modem(tp, 1);
2851541Srgrimes	tp->t_lflag &= ~EXTPROC;
286130263Sphk	pt = dev->si_drv1;
287130263Sphk	pt->pt_prison = td->td_ucred->cr_prison;
288130263Sphk	pt->pt_flags = 0;
289130263Sphk	pt->pt_send = 0;
290130263Sphk	pt->pt_ucntl = 0;
2911541Srgrimes	return (0);
2921541Srgrimes}
2931541Srgrimes
29412675Sjulianstatic	int
295130585Sphkptcclose(struct cdev *dev, int flags, int fmt, struct thread *td)
2961541Srgrimes{
297111742Sdes	struct tty *tp;
2981541Srgrimes
29950652Sphk	tp = dev->si_tty;
300130077Sphk	(void)ttyld_modem(tp, 0);
3019824Sbde
3029824Sbde	/*
3039824Sbde	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
3049824Sbde	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
3059824Sbde	 * l_modem()s that ignore carrier drop make no sense for ptys but
3069824Sbde	 * may be in use because other parts of the line discipline make
3079824Sbde	 * sense for ptys.  Recover by doing everything that a normal
3089824Sbde	 * ttymodem() would have done except for sending a SIGHUP.
3099824Sbde	 */
3109850Sbde	if (tp->t_state & TS_ISOPEN) {
3119850Sbde		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
3129850Sbde		tp->t_state |= TS_ZOMBIE;
3139850Sbde		ttyflush(tp, FREAD | FWRITE);
3149850Sbde	}
3159824Sbde
3161541Srgrimes	tp->t_oproc = 0;		/* mark closed */
3171541Srgrimes	return (0);
3181541Srgrimes}
3191541Srgrimes
32012675Sjulianstatic	int
321130585Sphkptcread(struct cdev *dev, struct uio *uio, int flag)
3221541Srgrimes{
323111742Sdes	struct tty *tp = dev->si_tty;
324130263Sphk	struct ptsc *pt = dev->si_drv1;
3251541Srgrimes	char buf[BUFSIZ];
3261541Srgrimes	int error = 0, cc;
3271541Srgrimes
3281541Srgrimes	/*
3291541Srgrimes	 * We want to block until the slave
3301541Srgrimes	 * is open, and there's something to read;
3311541Srgrimes	 * but if we lost the slave or we're NBIO,
3321541Srgrimes	 * then return the appropriate error instead.
3331541Srgrimes	 */
3341541Srgrimes	for (;;) {
3351541Srgrimes		if (tp->t_state&TS_ISOPEN) {
336130263Sphk			if (pt->pt_flags&PF_PKT && pt->pt_send) {
337130263Sphk				error = ureadc((int)pt->pt_send, uio);
3381541Srgrimes				if (error)
3391541Srgrimes					return (error);
340130263Sphk				if (pt->pt_send & TIOCPKT_IOCTL) {
3411541Srgrimes					cc = min(uio->uio_resid,
3421541Srgrimes						sizeof(tp->t_termios));
343111741Sdes					uiomove(&tp->t_termios, cc, uio);
3441541Srgrimes				}
345130263Sphk				pt->pt_send = 0;
3461541Srgrimes				return (0);
3471541Srgrimes			}
348130263Sphk			if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) {
349130263Sphk				error = ureadc((int)pt->pt_ucntl, uio);
3501541Srgrimes				if (error)
3511541Srgrimes					return (error);
352130263Sphk				pt->pt_ucntl = 0;
3531541Srgrimes				return (0);
3541541Srgrimes			}
3551541Srgrimes			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
3561541Srgrimes				break;
3571541Srgrimes		}
3589824Sbde		if ((tp->t_state & TS_CONNECTED) == 0)
3591541Srgrimes			return (0);	/* EOF */
360139205Sphk		if (flag & O_NONBLOCK)
3611541Srgrimes			return (EWOULDBLOCK);
3629639Sbde		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
3633308Sphk		if (error)
3641541Srgrimes			return (error);
3651541Srgrimes	}
366130263Sphk	if (pt->pt_flags & (PF_PKT|PF_UCNTL))
3671541Srgrimes		error = ureadc(0, uio);
3681541Srgrimes	while (uio->uio_resid > 0 && error == 0) {
3691541Srgrimes		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
3701541Srgrimes		if (cc <= 0)
3711541Srgrimes			break;
3721541Srgrimes		error = uiomove(buf, cc, uio);
3731541Srgrimes	}
3749626Sbde	ttwwakeup(tp);
3751541Srgrimes	return (error);
3761541Srgrimes}
3771541Srgrimes
37812675Sjulianstatic	void
379130262Sphkptsstop(struct tty *tp, int flush)
3801541Srgrimes{
381135298Sphk	struct ptsc *pt = tp->t_sc;
3821541Srgrimes	int flag;
3831541Srgrimes
3841541Srgrimes	/* note: FLUSHREAD and FLUSHWRITE already ok */
3851541Srgrimes	if (flush == 0) {
3861541Srgrimes		flush = TIOCPKT_STOP;
387130263Sphk		pt->pt_flags |= PF_STOPPED;
3881541Srgrimes	} else
389130263Sphk		pt->pt_flags &= ~PF_STOPPED;
390130263Sphk	pt->pt_send |= flush;
3911541Srgrimes	/* change of perspective */
3921541Srgrimes	flag = 0;
3931541Srgrimes	if (flush & FREAD)
3941541Srgrimes		flag |= FWRITE;
3951541Srgrimes	if (flush & FWRITE)
3961541Srgrimes		flag |= FREAD;
3971541Srgrimes	ptcwakeup(tp, flag);
3981541Srgrimes}
3991541Srgrimes
40012675Sjulianstatic	int
401130585Sphkptcpoll(struct cdev *dev, int events, struct thread *td)
4021541Srgrimes{
403111742Sdes	struct tty *tp = dev->si_tty;
404130263Sphk	struct ptsc *pt = dev->si_drv1;
40529354Speter	int revents = 0;
4061541Srgrimes	int s;
4071541Srgrimes
4089824Sbde	if ((tp->t_state & TS_CONNECTED) == 0)
409120513Sphk		return (events &
410120513Sphk		   (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
4111541Srgrimes
41229354Speter	/*
41329354Speter	 * Need to block timeouts (ttrstart).
41429354Speter	 */
41529354Speter	s = spltty();
4161541Srgrimes
41729354Speter	if (events & (POLLIN | POLLRDNORM))
41829354Speter		if ((tp->t_state & TS_ISOPEN) &&
41929354Speter		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
420130263Sphk		     ((pt->pt_flags & PF_PKT) && pt->pt_send) ||
421130263Sphk		     ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl)))
42229354Speter			revents |= events & (POLLIN | POLLRDNORM);
4231541Srgrimes
42429354Speter	if (events & (POLLOUT | POLLWRNORM))
42529354Speter		if (tp->t_state & TS_ISOPEN &&
426131114Sphk		    (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
42790831Sdillon		      (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
42829354Speter			revents |= events & (POLLOUT | POLLWRNORM);
4291541Srgrimes
43029354Speter	if (events & POLLHUP)
43129354Speter		if ((tp->t_state & TS_CARR_ON) == 0)
43229354Speter			revents |= POLLHUP;
4331541Srgrimes
43429354Speter	if (revents == 0) {
43529354Speter		if (events & (POLLIN | POLLRDNORM))
436130263Sphk			selrecord(td, &pt->pt_selr);
43729354Speter
438111742Sdes		if (events & (POLLOUT | POLLWRNORM))
439130263Sphk			selrecord(td, &pt->pt_selw);
4401541Srgrimes	}
44129354Speter	splx(s);
44229354Speter
44329354Speter	return (revents);
4441541Srgrimes}
4451541Srgrimes
44612675Sjulianstatic	int
447130585Sphkptcwrite(struct cdev *dev, struct uio *uio, int flag)
4481541Srgrimes{
449111742Sdes	struct tty *tp = dev->si_tty;
450111742Sdes	u_char *cp = 0;
451111742Sdes	int cc = 0;
4521541Srgrimes	u_char locbuf[BUFSIZ];
4531541Srgrimes	int cnt = 0;
4541541Srgrimes	int error = 0;
4551541Srgrimes
4561541Srgrimesagain:
4571541Srgrimes	if ((tp->t_state&TS_ISOPEN) == 0)
4581541Srgrimes		goto block;
45911789Sbde	while (uio->uio_resid > 0 || cc > 0) {
4601541Srgrimes		if (cc == 0) {
4611541Srgrimes			cc = min(uio->uio_resid, BUFSIZ);
4621541Srgrimes			cp = locbuf;
463111741Sdes			error = uiomove(cp, cc, uio);
4641541Srgrimes			if (error)
4651541Srgrimes				return (error);
4661541Srgrimes			/* check again for safety */
46711789Sbde			if ((tp->t_state & TS_ISOPEN) == 0) {
46811789Sbde				/* adjust for data copied in but not written */
46911789Sbde				uio->uio_resid += cc;
4701541Srgrimes				return (EIO);
47111789Sbde			}
4721541Srgrimes		}
4731541Srgrimes		while (cc > 0) {
4741541Srgrimes			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
47590831Sdillon			   (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
4769824Sbde				wakeup(TSA_HUP_OR_INPUT(tp));
4771541Srgrimes				goto block;
4781541Srgrimes			}
479130077Sphk			ttyld_rint(tp, *cp++);
4801541Srgrimes			cnt++;
4811541Srgrimes			cc--;
4821541Srgrimes		}
4831541Srgrimes		cc = 0;
4841541Srgrimes	}
4851541Srgrimes	return (0);
4861541Srgrimesblock:
4871541Srgrimes	/*
4881541Srgrimes	 * Come here to wait for slave to open, for space
48915199Sbde	 * in outq, or space in rawq, or an empty canq.
4901541Srgrimes	 */
49111789Sbde	if ((tp->t_state & TS_CONNECTED) == 0) {
49211789Sbde		/* adjust for data copied in but not written */
49311789Sbde		uio->uio_resid += cc;
4941541Srgrimes		return (EIO);
49511789Sbde	}
496139205Sphk	if (flag & O_NONBLOCK) {
4971541Srgrimes		/* adjust for data copied in but not written */
4981541Srgrimes		uio->uio_resid += cc;
4991541Srgrimes		if (cnt == 0)
5001541Srgrimes			return (EWOULDBLOCK);
5011541Srgrimes		return (0);
5021541Srgrimes	}
5039639Sbde	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
5043308Sphk	if (error) {
5051541Srgrimes		/* adjust for data copied in but not written */
5061541Srgrimes		uio->uio_resid += cc;
5071541Srgrimes		return (error);
5081541Srgrimes	}
5091541Srgrimes	goto again;
5101541Srgrimes}
5111541Srgrimes
5121541Srgrimes/*ARGSUSED*/
51312675Sjulianstatic	int
514135622Sphkptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
5151541Srgrimes{
516111742Sdes	struct tty *tp = dev->si_tty;
517130263Sphk	struct ptsc *pt = dev->si_drv1;
5181541Srgrimes
519135622Sphk	switch (cmd) {
5201541Srgrimes
521135622Sphk	case TIOCGPGRP:
522135622Sphk		/*
523135622Sphk		 * We avoid calling ttioctl on the controller since,
524135622Sphk		 * in that case, tp must be the controlling terminal.
525135622Sphk		 */
526135622Sphk		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
527135622Sphk		return (0);
5281541Srgrimes
529135622Sphk	case TIOCPKT:
530135622Sphk		if (*(int *)data) {
531135622Sphk			if (pt->pt_flags & PF_UCNTL)
532135622Sphk				return (EINVAL);
533135622Sphk			pt->pt_flags |= PF_PKT;
534135622Sphk		} else
535135622Sphk			pt->pt_flags &= ~PF_PKT;
536135622Sphk		return (0);
5371541Srgrimes
538135622Sphk	case TIOCUCNTL:
539135622Sphk		if (*(int *)data) {
540135622Sphk			if (pt->pt_flags & PF_PKT)
541135622Sphk				return (EINVAL);
542135622Sphk			pt->pt_flags |= PF_UCNTL;
543135622Sphk		} else
544135622Sphk			pt->pt_flags &= ~PF_UCNTL;
545135622Sphk		return (0);
546135622Sphk	}
5471541Srgrimes
548135622Sphk	/*
549135622Sphk	 * The rest of the ioctls shouldn't be called until
550135622Sphk	 * the slave is open.
551135622Sphk	 */
552135622Sphk	if ((tp->t_state & TS_ISOPEN) == 0)
553135622Sphk		return (EAGAIN);
55447203Sluoqi
555135622Sphk	switch (cmd) {
556130892Sphk#ifndef BURN_BRIDGES
5571541Srgrimes#ifdef COMPAT_43
558135622Sphk	case TIOCSETP:
559135622Sphk	case TIOCSETN:
5601541Srgrimes#endif
561130892Sphk#endif
562135622Sphk	case TIOCSETD:
563135622Sphk	case TIOCSETA:
564135622Sphk	case TIOCSETAW:
565135622Sphk	case TIOCSETAF:
566135622Sphk		/*
567135622Sphk		 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
568135622Sphk		 * ttywflush(tp) will hang if there are characters in
569135622Sphk		 * the outq.
570135622Sphk		 */
571135622Sphk		ndflush(&tp->t_outq, tp->t_outq.c_cc);
572135622Sphk		break;
5731541Srgrimes
574135622Sphk	case TIOCSIG:
575135622Sphk		if (*(unsigned int *)data >= NSIG ||
576135622Sphk		    *(unsigned int *)data == 0)
577135622Sphk			return(EINVAL);
578135622Sphk		if ((tp->t_lflag&NOFLSH) == 0)
579135622Sphk			ttyflush(tp, FREAD|FWRITE);
580135622Sphk		if (tp->t_pgrp != NULL) {
581135622Sphk			PGRP_LOCK(tp->t_pgrp);
582135622Sphk			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
583135622Sphk			PGRP_UNLOCK(tp->t_pgrp);
5841541Srgrimes		}
585135622Sphk		if ((*(unsigned int *)data == SIGINFO) &&
586135622Sphk		    ((tp->t_lflag&NOKERNINFO) == 0))
587135622Sphk			ttyinfo(tp);
588135622Sphk		return(0);
58947203Sluoqi	}
590135622Sphk
591135622Sphk	return (ptsioctl(dev, cmd, data, flag, td));
592135622Sphk}
593135622Sphk
594135622Sphk/*ARGSUSED*/
595135622Sphkstatic	int
596135622Sphkptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
597135622Sphk{
598135622Sphk	struct tty *tp = dev->si_tty;
599135622Sphk	struct ptsc *pt = dev->si_drv1;
600135622Sphk	u_char *cc = tp->t_cc;
601135622Sphk	int stop, error;
602135622Sphk
60347301Sluoqi	if (cmd == TIOCEXT) {
60447301Sluoqi		/*
60547301Sluoqi		 * When the EXTPROC bit is being toggled, we need
60647301Sluoqi		 * to send an TIOCPKT_IOCTL if the packet driver
60747301Sluoqi		 * is turned on.
60847301Sluoqi		 */
60947301Sluoqi		if (*(int *)data) {
610130263Sphk			if (pt->pt_flags & PF_PKT) {
611130263Sphk				pt->pt_send |= TIOCPKT_IOCTL;
61247301Sluoqi				ptcwakeup(tp, FREAD);
61347301Sluoqi			}
61447301Sluoqi			tp->t_lflag |= EXTPROC;
61547301Sluoqi		} else {
61647301Sluoqi			if ((tp->t_lflag & EXTPROC) &&
617130263Sphk			    (pt->pt_flags & PF_PKT)) {
618130263Sphk				pt->pt_send |= TIOCPKT_IOCTL;
61947301Sluoqi				ptcwakeup(tp, FREAD);
62047301Sluoqi			}
62147301Sluoqi			tp->t_lflag &= ~EXTPROC;
62247301Sluoqi		}
62347301Sluoqi		return(0);
62447301Sluoqi	}
625130054Sphk	error = ttyioctl(dev, cmd, data, flag, td);
626130054Sphk	if (error == ENOTTY) {
627130263Sphk		if (pt->pt_flags & PF_UCNTL &&
6281541Srgrimes		    (cmd & ~0xff) == UIOCCMD(0)) {
6291541Srgrimes			if (cmd & 0xff) {
630130263Sphk				pt->pt_ucntl = (u_char)cmd;
6311541Srgrimes				ptcwakeup(tp, FREAD);
6321541Srgrimes			}
6331541Srgrimes			return (0);
6341541Srgrimes		}
6351541Srgrimes		error = ENOTTY;
6361541Srgrimes	}
6371541Srgrimes	/*
6381541Srgrimes	 * If external processing and packet mode send ioctl packet.
6391541Srgrimes	 */
640130263Sphk	if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) {
6411541Srgrimes		switch(cmd) {
6421541Srgrimes		case TIOCSETA:
6431541Srgrimes		case TIOCSETAW:
6441541Srgrimes		case TIOCSETAF:
645130892Sphk#ifndef BURN_BRIDGES
6461541Srgrimes#ifdef COMPAT_43
6471541Srgrimes		case TIOCSETP:
6481541Srgrimes		case TIOCSETN:
6491541Srgrimes		case TIOCSETC:
6501541Srgrimes		case TIOCSLTC:
6511541Srgrimes		case TIOCLBIS:
6521541Srgrimes		case TIOCLBIC:
6531541Srgrimes		case TIOCLSET:
6541541Srgrimes#endif
655130892Sphk#endif
656130263Sphk			pt->pt_send |= TIOCPKT_IOCTL;
6571541Srgrimes			ptcwakeup(tp, FREAD);
658115463Sphk			break;
6591541Srgrimes		default:
6601541Srgrimes			break;
6611541Srgrimes		}
6621541Srgrimes	}
6638876Srgrimes	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
6641541Srgrimes		&& CCEQ(cc[VSTART], CTRL('q'));
665130263Sphk	if (pt->pt_flags & PF_NOSTOP) {
6661541Srgrimes		if (stop) {
667130263Sphk			pt->pt_send &= ~TIOCPKT_NOSTOP;
668130263Sphk			pt->pt_send |= TIOCPKT_DOSTOP;
669130263Sphk			pt->pt_flags &= ~PF_NOSTOP;
6701541Srgrimes			ptcwakeup(tp, FREAD);
6711541Srgrimes		}
6721541Srgrimes	} else {
6731541Srgrimes		if (!stop) {
674130263Sphk			pt->pt_send &= ~TIOCPKT_DOSTOP;
675130263Sphk			pt->pt_send |= TIOCPKT_NOSTOP;
676130263Sphk			pt->pt_flags |= PF_NOSTOP;
6771541Srgrimes			ptcwakeup(tp, FREAD);
6781541Srgrimes		}
6791541Srgrimes	}
6801541Srgrimes	return (error);
6811541Srgrimes}
68212517Sjulian
68312675Sjulianstatic void
684147982Srwatsonpty_clone(void *arg, struct ucred *cr, char *name, int namelen,
685147982Srwatson    struct cdev **dev)
68664880Sphk{
68764880Sphk	int u;
68864880Sphk
689130640Sphk	if (*dev != NULL)
69064880Sphk		return;
69164880Sphk	if (bcmp(name, "pty", 3) != 0)
69264880Sphk		return;
69364880Sphk	if (name[5] != '\0')
69464880Sphk		return;
69564880Sphk	switch (name[3]) {
69664880Sphk	case 'p': u =   0; break;
69764880Sphk	case 'q': u =  32; break;
69864880Sphk	case 'r': u =  64; break;
69964880Sphk	case 's': u =  96; break;
70064880Sphk	case 'P': u = 128; break;
70164880Sphk	case 'Q': u = 160; break;
70264880Sphk	case 'R': u = 192; break;
70364880Sphk	case 'S': u = 224; break;
70464880Sphk	default: return;
70564880Sphk	}
70664880Sphk	if (name[4] >= '0' && name[4] <= '9')
70764880Sphk		u += name[4] - '0';
70864880Sphk	else if (name[4] >= 'a' && name[4] <= 'v')
70964880Sphk		u += name[4] - 'a' + 10;
71064880Sphk	else
71164880Sphk		return;
712147982Srwatson	*dev = make_dev_cred(&ptc_cdevsw, u, cr,
71377176Sphk	    UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32);
714144389Sphk	dev_ref(*dev);
71577176Sphk	(*dev)->si_flags |= SI_CHEAPCLONE;
71664880Sphk	return;
71764880Sphk}
71864880Sphk
71964880Sphkstatic void
720130262Sphkptc_drvinit(void *unused)
72112517Sjulian{
722108363Sphk
723147982Srwatson	EVENTHANDLER_REGISTER(dev_clone_cred, pty_clone, 0, 1000);
72412517Sjulian}
72512517Sjulian
726142709SphkSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,ptc_drvinit,NULL)
727