pty.c revision 136680
11541Srgrimes/*
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 136680 2004-10-18 21:51:27Z phk $");
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>
571541Srgrimes#include <sys/vnode.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);
66130585Sphkstatic struct cdev *ptyinit(struct cdev *cdev);
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
8038485Sbde#define	CDEV_MAJOR_S	5
8147625Sphkstatic struct cdevsw pts_cdevsw = {
82126080Sphk	.d_version =	D_VERSION,
83111815Sphk	.d_open =	ptsopen,
84111815Sphk	.d_close =	ptsclose,
85111815Sphk	.d_read =	ptsread,
86111815Sphk	.d_write =	ptswrite,
87135622Sphk	.d_ioctl =	ptsioctl,
88111815Sphk	.d_name =	"pts",
89111815Sphk	.d_maj =	CDEV_MAJOR_S,
90126080Sphk	.d_flags =	D_TTY | D_NEEDGIANT,
9138485Sbde};
9212675Sjulian
9338485Sbde#define	CDEV_MAJOR_C	6
9447625Sphkstatic struct cdevsw ptc_cdevsw = {
95126080Sphk	.d_version =	D_VERSION,
96111815Sphk	.d_open =	ptcopen,
97111815Sphk	.d_close =	ptcclose,
98111815Sphk	.d_read =	ptcread,
99111815Sphk	.d_write =	ptcwrite,
100135622Sphk	.d_ioctl =	ptcioctl,
101111815Sphk	.d_poll =	ptcpoll,
102111815Sphk	.d_name =	"ptc",
103111815Sphk	.d_maj =	CDEV_MAJOR_C,
104126080Sphk	.d_flags =	D_TTY | D_NEEDGIANT,
10538485Sbde};
10612675Sjulian
1071541Srgrimes#define BUFSIZ 100		/* Chunk size iomoved to/from user */
1081541Srgrimes
109130263Sphkstruct	ptsc {
1101541Srgrimes	int	pt_flags;
1111541Srgrimes	struct	selinfo pt_selr, pt_selw;
1121541Srgrimes	u_char	pt_send;
1131541Srgrimes	u_char	pt_ucntl;
114130054Sphk	struct tty *pt_tty;
115130585Sphk	struct cdev *devs, *devc;
11657070Srwatson	struct	prison *pt_prison;
11749536Sphk};
1181541Srgrimes
1191541Srgrimes#define	PF_PKT		0x08		/* packet mode */
1201541Srgrimes#define	PF_STOPPED	0x10		/* user told stopped */
1211541Srgrimes#define	PF_NOSTOP	0x40
1221541Srgrimes#define PF_UCNTL	0x80		/* user control mode */
1231541Srgrimes
124130259Sphk#define	TSA_PTC_READ(tp)	((void *)&(tp)->t_outq.c_cf)
125130259Sphk#define	TSA_PTC_WRITE(tp)	((void *)&(tp)->t_rawq.c_cl)
126130259Sphk#define	TSA_PTS_READ(tp)	((void *)&(tp)->t_canq)
127130259Sphk
12877176Sphkstatic char *names = "pqrsPQRS";
1291541Srgrimes/*
13049536Sphk * This function creates and initializes a pts/ptc pair
1311541Srgrimes *
13249536Sphk * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
13349536Sphk * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
13449536Sphk *
135111742Sdes * XXX: define and add mapping of upper minor bits to allow more
13649536Sphk *      than 256 ptys.
1371541Srgrimes */
138130585Sphkstatic struct cdev *
139130585Sphkptyinit(struct cdev *devc)
1401541Srgrimes{
141130585Sphk	struct cdev *devs;
142130263Sphk	struct ptsc *pt;
14377176Sphk	int n;
1441541Srgrimes
14577176Sphk	n = minor(devc);
14649536Sphk	/* For now we only map the lower 8 bits of the minor */
14749536Sphk	if (n & ~0xff)
148130640Sphk		return (NULL);
14949536Sphk
15078405Sbrian	devc->si_flags &= ~SI_CHEAPCLONE;
15178405Sbrian
152111119Simp	pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
15350092Sjulian	pt->devs = devs = make_dev(&pts_cdevsw, n,
15466067Sphk	    UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32);
15577176Sphk	pt->devc = devc;
15649536Sphk
157130054Sphk	pt->pt_tty = ttymalloc(pt->pt_tty);
158135298Sphk	pt->pt_tty->t_sc = pt;
15949536Sphk	devs->si_drv1 = devc->si_drv1 = pt;
160130054Sphk	devs->si_tty = devc->si_tty = pt->pt_tty;
161130054Sphk	pt->pt_tty->t_dev = devs;
16264880Sphk	return (devc);
16316322Sgpalmer}
1641541Srgrimes
1651541Srgrimes/*ARGSUSED*/
16612675Sjulianstatic	int
167130585Sphkptsopen(struct cdev *dev, int flag, int devtype, struct thread *td)
1681541Srgrimes{
169111742Sdes	struct tty *tp;
1701541Srgrimes	int error;
171130263Sphk	struct ptsc *pt;
1721541Srgrimes
17349536Sphk	if (!dev->si_drv1)
174111742Sdes		return(ENXIO);
175130263Sphk	pt = dev->si_drv1;
17650652Sphk	tp = dev->si_tty;
1771541Srgrimes	if ((tp->t_state & TS_ISOPEN) == 0) {
178136680Sphk		ttyinitmode(tp, 1, 0);
179125839Srwatson	} else if (tp->t_state & TS_XCLUDE && suser(td))
1801541Srgrimes		return (EBUSY);
181130263Sphk	else if (pt->pt_prison != td->td_ucred->cr_prison)
18257070Srwatson		return (EBUSY);
1831541Srgrimes	if (tp->t_oproc)			/* Ctrlr still around. */
184130077Sphk		(void)ttyld_modem(tp, 1);
1851541Srgrimes	while ((tp->t_state & TS_CARR_ON) == 0) {
1861541Srgrimes		if (flag&FNONBLOCK)
1871541Srgrimes			break;
1889639Sbde		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
1899624Sbde				 "ptsopn", 0);
1903308Sphk		if (error)
1911541Srgrimes			return (error);
1921541Srgrimes	}
193130077Sphk	error = ttyld_open(tp, dev);
1947724Sache	if (error == 0)
1957724Sache		ptcwakeup(tp, FREAD|FWRITE);
1961541Srgrimes	return (error);
1971541Srgrimes}
1981541Srgrimes
19912675Sjulianstatic	int
200130585Sphkptsclose(struct cdev *dev, int flag, int mode, struct thread *td)
2011541Srgrimes{
202111742Sdes	struct tty *tp;
2031541Srgrimes	int err;
2041541Srgrimes
20550652Sphk	tp = dev->si_tty;
206130077Sphk	err = ttyld_close(tp, flag);
207132226Sphk	(void) tty_close(tp);
2081541Srgrimes	return (err);
2091541Srgrimes}
2101541Srgrimes
21112675Sjulianstatic	int
212130585Sphkptsread(struct cdev *dev, struct uio *uio, int flag)
2131541Srgrimes{
214111742Sdes	struct tty *tp = dev->si_tty;
2151541Srgrimes	int error = 0;
2161541Srgrimes
217131114Sphk	if (tp->t_oproc)
218131114Sphk		error = ttyld_read(tp, uio, flag);
2191541Srgrimes	ptcwakeup(tp, FWRITE);
2201541Srgrimes	return (error);
2211541Srgrimes}
2221541Srgrimes
2231541Srgrimes/*
2241541Srgrimes * Write to pseudo-tty.
2251541Srgrimes * Wakeups of controlling tty will happen
2261541Srgrimes * indirectly, when tty driver calls ptsstart.
2271541Srgrimes */
22812675Sjulianstatic	int
229130585Sphkptswrite(struct cdev *dev, struct uio *uio, int flag)
2301541Srgrimes{
231111742Sdes	struct tty *tp;
2321541Srgrimes
23350652Sphk	tp = dev->si_tty;
2341541Srgrimes	if (tp->t_oproc == 0)
2351541Srgrimes		return (EIO);
236130077Sphk	return (ttyld_write(tp, uio, flag));
2371541Srgrimes}
2381541Srgrimes
2391541Srgrimes/*
2401541Srgrimes * Start output on pseudo-tty.
2411541Srgrimes * Wake up process selecting or sleeping for input from controlling tty.
2421541Srgrimes */
24312819Sphkstatic void
244130262Sphkptsstart(struct tty *tp)
2451541Srgrimes{
246135298Sphk	struct ptsc *pt = tp->t_sc;
2471541Srgrimes
2481541Srgrimes	if (tp->t_state & TS_TTSTOP)
2491541Srgrimes		return;
250130263Sphk	if (pt->pt_flags & PF_STOPPED) {
251130263Sphk		pt->pt_flags &= ~PF_STOPPED;
252130263Sphk		pt->pt_send = TIOCPKT_START;
2531541Srgrimes	}
2541541Srgrimes	ptcwakeup(tp, FREAD);
2551541Srgrimes}
2561541Srgrimes
25712819Sphkstatic void
258130262Sphkptcwakeup(struct tty *tp, int flag)
2591541Srgrimes{
260135298Sphk	struct ptsc *pt = tp->t_sc;
2611541Srgrimes
2621541Srgrimes	if (flag & FREAD) {
263130263Sphk		selwakeuppri(&pt->pt_selr, TTIPRI);
2649639Sbde		wakeup(TSA_PTC_READ(tp));
2651541Srgrimes	}
2661541Srgrimes	if (flag & FWRITE) {
267130263Sphk		selwakeuppri(&pt->pt_selw, TTOPRI);
2689639Sbde		wakeup(TSA_PTC_WRITE(tp));
2691541Srgrimes	}
2701541Srgrimes}
2711541Srgrimes
27212675Sjulianstatic	int
273130585Sphkptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
2741541Srgrimes{
275111742Sdes	struct tty *tp;
276130263Sphk	struct ptsc *pt;
2771541Srgrimes
27849536Sphk	if (!dev->si_drv1)
27977176Sphk		ptyinit(dev);
28049536Sphk	if (!dev->si_drv1)
281111742Sdes		return(ENXIO);
28250652Sphk	tp = dev->si_tty;
2831541Srgrimes	if (tp->t_oproc)
2841541Srgrimes		return (EIO);
28559818Sache	tp->t_timeout = -1;
2861541Srgrimes	tp->t_oproc = ptsstart;
28751654Sphk	tp->t_stop = ptsstop;
288130077Sphk	(void)ttyld_modem(tp, 1);
2891541Srgrimes	tp->t_lflag &= ~EXTPROC;
290130263Sphk	pt = dev->si_drv1;
291130263Sphk	pt->pt_prison = td->td_ucred->cr_prison;
292130263Sphk	pt->pt_flags = 0;
293130263Sphk	pt->pt_send = 0;
294130263Sphk	pt->pt_ucntl = 0;
2951541Srgrimes	return (0);
2961541Srgrimes}
2971541Srgrimes
29812675Sjulianstatic	int
299130585Sphkptcclose(struct cdev *dev, int flags, int fmt, struct thread *td)
3001541Srgrimes{
301111742Sdes	struct tty *tp;
3021541Srgrimes
30350652Sphk	tp = dev->si_tty;
304130077Sphk	(void)ttyld_modem(tp, 0);
3059824Sbde
3069824Sbde	/*
3079824Sbde	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
3089824Sbde	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
3099824Sbde	 * l_modem()s that ignore carrier drop make no sense for ptys but
3109824Sbde	 * may be in use because other parts of the line discipline make
3119824Sbde	 * sense for ptys.  Recover by doing everything that a normal
3129824Sbde	 * ttymodem() would have done except for sending a SIGHUP.
3139824Sbde	 */
3149850Sbde	if (tp->t_state & TS_ISOPEN) {
3159850Sbde		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
3169850Sbde		tp->t_state |= TS_ZOMBIE;
3179850Sbde		ttyflush(tp, FREAD | FWRITE);
3189850Sbde	}
3199824Sbde
3201541Srgrimes	tp->t_oproc = 0;		/* mark closed */
3211541Srgrimes	return (0);
3221541Srgrimes}
3231541Srgrimes
32412675Sjulianstatic	int
325130585Sphkptcread(struct cdev *dev, struct uio *uio, int flag)
3261541Srgrimes{
327111742Sdes	struct tty *tp = dev->si_tty;
328130263Sphk	struct ptsc *pt = dev->si_drv1;
3291541Srgrimes	char buf[BUFSIZ];
3301541Srgrimes	int error = 0, cc;
3311541Srgrimes
3321541Srgrimes	/*
3331541Srgrimes	 * We want to block until the slave
3341541Srgrimes	 * is open, and there's something to read;
3351541Srgrimes	 * but if we lost the slave or we're NBIO,
3361541Srgrimes	 * then return the appropriate error instead.
3371541Srgrimes	 */
3381541Srgrimes	for (;;) {
3391541Srgrimes		if (tp->t_state&TS_ISOPEN) {
340130263Sphk			if (pt->pt_flags&PF_PKT && pt->pt_send) {
341130263Sphk				error = ureadc((int)pt->pt_send, uio);
3421541Srgrimes				if (error)
3431541Srgrimes					return (error);
344130263Sphk				if (pt->pt_send & TIOCPKT_IOCTL) {
3451541Srgrimes					cc = min(uio->uio_resid,
3461541Srgrimes						sizeof(tp->t_termios));
347111741Sdes					uiomove(&tp->t_termios, cc, uio);
3481541Srgrimes				}
349130263Sphk				pt->pt_send = 0;
3501541Srgrimes				return (0);
3511541Srgrimes			}
352130263Sphk			if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) {
353130263Sphk				error = ureadc((int)pt->pt_ucntl, uio);
3541541Srgrimes				if (error)
3551541Srgrimes					return (error);
356130263Sphk				pt->pt_ucntl = 0;
3571541Srgrimes				return (0);
3581541Srgrimes			}
3591541Srgrimes			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
3601541Srgrimes				break;
3611541Srgrimes		}
3629824Sbde		if ((tp->t_state & TS_CONNECTED) == 0)
3631541Srgrimes			return (0);	/* EOF */
3641541Srgrimes		if (flag & IO_NDELAY)
3651541Srgrimes			return (EWOULDBLOCK);
3669639Sbde		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
3673308Sphk		if (error)
3681541Srgrimes			return (error);
3691541Srgrimes	}
370130263Sphk	if (pt->pt_flags & (PF_PKT|PF_UCNTL))
3711541Srgrimes		error = ureadc(0, uio);
3721541Srgrimes	while (uio->uio_resid > 0 && error == 0) {
3731541Srgrimes		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
3741541Srgrimes		if (cc <= 0)
3751541Srgrimes			break;
3761541Srgrimes		error = uiomove(buf, cc, uio);
3771541Srgrimes	}
3789626Sbde	ttwwakeup(tp);
3791541Srgrimes	return (error);
3801541Srgrimes}
3811541Srgrimes
38212675Sjulianstatic	void
383130262Sphkptsstop(struct tty *tp, int flush)
3841541Srgrimes{
385135298Sphk	struct ptsc *pt = tp->t_sc;
3861541Srgrimes	int flag;
3871541Srgrimes
3881541Srgrimes	/* note: FLUSHREAD and FLUSHWRITE already ok */
3891541Srgrimes	if (flush == 0) {
3901541Srgrimes		flush = TIOCPKT_STOP;
391130263Sphk		pt->pt_flags |= PF_STOPPED;
3921541Srgrimes	} else
393130263Sphk		pt->pt_flags &= ~PF_STOPPED;
394130263Sphk	pt->pt_send |= flush;
3951541Srgrimes	/* change of perspective */
3961541Srgrimes	flag = 0;
3971541Srgrimes	if (flush & FREAD)
3981541Srgrimes		flag |= FWRITE;
3991541Srgrimes	if (flush & FWRITE)
4001541Srgrimes		flag |= FREAD;
4011541Srgrimes	ptcwakeup(tp, flag);
4021541Srgrimes}
4031541Srgrimes
40412675Sjulianstatic	int
405130585Sphkptcpoll(struct cdev *dev, int events, struct thread *td)
4061541Srgrimes{
407111742Sdes	struct tty *tp = dev->si_tty;
408130263Sphk	struct ptsc *pt = dev->si_drv1;
40929354Speter	int revents = 0;
4101541Srgrimes	int s;
4111541Srgrimes
4129824Sbde	if ((tp->t_state & TS_CONNECTED) == 0)
413120513Sphk		return (events &
414120513Sphk		   (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
4151541Srgrimes
41629354Speter	/*
41729354Speter	 * Need to block timeouts (ttrstart).
41829354Speter	 */
41929354Speter	s = spltty();
4201541Srgrimes
42129354Speter	if (events & (POLLIN | POLLRDNORM))
42229354Speter		if ((tp->t_state & TS_ISOPEN) &&
42329354Speter		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
424130263Sphk		     ((pt->pt_flags & PF_PKT) && pt->pt_send) ||
425130263Sphk		     ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl)))
42629354Speter			revents |= events & (POLLIN | POLLRDNORM);
4271541Srgrimes
42829354Speter	if (events & (POLLOUT | POLLWRNORM))
42929354Speter		if (tp->t_state & TS_ISOPEN &&
430131114Sphk		    (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
43190831Sdillon		      (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
43229354Speter			revents |= events & (POLLOUT | POLLWRNORM);
4331541Srgrimes
43429354Speter	if (events & POLLHUP)
43529354Speter		if ((tp->t_state & TS_CARR_ON) == 0)
43629354Speter			revents |= POLLHUP;
4371541Srgrimes
43829354Speter	if (revents == 0) {
43929354Speter		if (events & (POLLIN | POLLRDNORM))
440130263Sphk			selrecord(td, &pt->pt_selr);
44129354Speter
442111742Sdes		if (events & (POLLOUT | POLLWRNORM))
443130263Sphk			selrecord(td, &pt->pt_selw);
4441541Srgrimes	}
44529354Speter	splx(s);
44629354Speter
44729354Speter	return (revents);
4481541Srgrimes}
4491541Srgrimes
45012675Sjulianstatic	int
451130585Sphkptcwrite(struct cdev *dev, struct uio *uio, int flag)
4521541Srgrimes{
453111742Sdes	struct tty *tp = dev->si_tty;
454111742Sdes	u_char *cp = 0;
455111742Sdes	int cc = 0;
4561541Srgrimes	u_char locbuf[BUFSIZ];
4571541Srgrimes	int cnt = 0;
4581541Srgrimes	int error = 0;
4591541Srgrimes
4601541Srgrimesagain:
4611541Srgrimes	if ((tp->t_state&TS_ISOPEN) == 0)
4621541Srgrimes		goto block;
46311789Sbde	while (uio->uio_resid > 0 || cc > 0) {
4641541Srgrimes		if (cc == 0) {
4651541Srgrimes			cc = min(uio->uio_resid, BUFSIZ);
4661541Srgrimes			cp = locbuf;
467111741Sdes			error = uiomove(cp, cc, uio);
4681541Srgrimes			if (error)
4691541Srgrimes				return (error);
4701541Srgrimes			/* check again for safety */
47111789Sbde			if ((tp->t_state & TS_ISOPEN) == 0) {
47211789Sbde				/* adjust for data copied in but not written */
47311789Sbde				uio->uio_resid += cc;
4741541Srgrimes				return (EIO);
47511789Sbde			}
4761541Srgrimes		}
4771541Srgrimes		while (cc > 0) {
4781541Srgrimes			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
47990831Sdillon			   (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
4809824Sbde				wakeup(TSA_HUP_OR_INPUT(tp));
4811541Srgrimes				goto block;
4821541Srgrimes			}
483130077Sphk			ttyld_rint(tp, *cp++);
4841541Srgrimes			cnt++;
4851541Srgrimes			cc--;
4861541Srgrimes		}
4871541Srgrimes		cc = 0;
4881541Srgrimes	}
4891541Srgrimes	return (0);
4901541Srgrimesblock:
4911541Srgrimes	/*
4921541Srgrimes	 * Come here to wait for slave to open, for space
49315199Sbde	 * in outq, or space in rawq, or an empty canq.
4941541Srgrimes	 */
49511789Sbde	if ((tp->t_state & TS_CONNECTED) == 0) {
49611789Sbde		/* adjust for data copied in but not written */
49711789Sbde		uio->uio_resid += cc;
4981541Srgrimes		return (EIO);
49911789Sbde	}
5001541Srgrimes	if (flag & IO_NDELAY) {
5011541Srgrimes		/* adjust for data copied in but not written */
5021541Srgrimes		uio->uio_resid += cc;
5031541Srgrimes		if (cnt == 0)
5041541Srgrimes			return (EWOULDBLOCK);
5051541Srgrimes		return (0);
5061541Srgrimes	}
5079639Sbde	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
5083308Sphk	if (error) {
5091541Srgrimes		/* adjust for data copied in but not written */
5101541Srgrimes		uio->uio_resid += cc;
5111541Srgrimes		return (error);
5121541Srgrimes	}
5131541Srgrimes	goto again;
5141541Srgrimes}
5151541Srgrimes
5161541Srgrimes/*ARGSUSED*/
51712675Sjulianstatic	int
518135622Sphkptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
5191541Srgrimes{
520111742Sdes	struct tty *tp = dev->si_tty;
521130263Sphk	struct ptsc *pt = dev->si_drv1;
5221541Srgrimes
523135622Sphk	switch (cmd) {
5241541Srgrimes
525135622Sphk	case TIOCGPGRP:
526135622Sphk		/*
527135622Sphk		 * We avoid calling ttioctl on the controller since,
528135622Sphk		 * in that case, tp must be the controlling terminal.
529135622Sphk		 */
530135622Sphk		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
531135622Sphk		return (0);
5321541Srgrimes
533135622Sphk	case TIOCPKT:
534135622Sphk		if (*(int *)data) {
535135622Sphk			if (pt->pt_flags & PF_UCNTL)
536135622Sphk				return (EINVAL);
537135622Sphk			pt->pt_flags |= PF_PKT;
538135622Sphk		} else
539135622Sphk			pt->pt_flags &= ~PF_PKT;
540135622Sphk		return (0);
5411541Srgrimes
542135622Sphk	case TIOCUCNTL:
543135622Sphk		if (*(int *)data) {
544135622Sphk			if (pt->pt_flags & PF_PKT)
545135622Sphk				return (EINVAL);
546135622Sphk			pt->pt_flags |= PF_UCNTL;
547135622Sphk		} else
548135622Sphk			pt->pt_flags &= ~PF_UCNTL;
549135622Sphk		return (0);
550135622Sphk	}
5511541Srgrimes
552135622Sphk	/*
553135622Sphk	 * The rest of the ioctls shouldn't be called until
554135622Sphk	 * the slave is open.
555135622Sphk	 */
556135622Sphk	if ((tp->t_state & TS_ISOPEN) == 0)
557135622Sphk		return (EAGAIN);
55847203Sluoqi
559135622Sphk	switch (cmd) {
560130892Sphk#ifndef BURN_BRIDGES
5611541Srgrimes#ifdef COMPAT_43
562135622Sphk	case TIOCSETP:
563135622Sphk	case TIOCSETN:
5641541Srgrimes#endif
565130892Sphk#endif
566135622Sphk	case TIOCSETD:
567135622Sphk	case TIOCSETA:
568135622Sphk	case TIOCSETAW:
569135622Sphk	case TIOCSETAF:
570135622Sphk		/*
571135622Sphk		 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
572135622Sphk		 * ttywflush(tp) will hang if there are characters in
573135622Sphk		 * the outq.
574135622Sphk		 */
575135622Sphk		ndflush(&tp->t_outq, tp->t_outq.c_cc);
576135622Sphk		break;
5771541Srgrimes
578135622Sphk	case TIOCSIG:
579135622Sphk		if (*(unsigned int *)data >= NSIG ||
580135622Sphk		    *(unsigned int *)data == 0)
581135622Sphk			return(EINVAL);
582135622Sphk		if ((tp->t_lflag&NOFLSH) == 0)
583135622Sphk			ttyflush(tp, FREAD|FWRITE);
584135622Sphk		if (tp->t_pgrp != NULL) {
585135622Sphk			PGRP_LOCK(tp->t_pgrp);
586135622Sphk			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
587135622Sphk			PGRP_UNLOCK(tp->t_pgrp);
5881541Srgrimes		}
589135622Sphk		if ((*(unsigned int *)data == SIGINFO) &&
590135622Sphk		    ((tp->t_lflag&NOKERNINFO) == 0))
591135622Sphk			ttyinfo(tp);
592135622Sphk		return(0);
59347203Sluoqi	}
594135622Sphk
595135622Sphk	return (ptsioctl(dev, cmd, data, flag, td));
596135622Sphk}
597135622Sphk
598135622Sphk/*ARGSUSED*/
599135622Sphkstatic	int
600135622Sphkptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
601135622Sphk{
602135622Sphk	struct tty *tp = dev->si_tty;
603135622Sphk	struct ptsc *pt = dev->si_drv1;
604135622Sphk	u_char *cc = tp->t_cc;
605135622Sphk	int stop, error;
606135622Sphk
60747301Sluoqi	if (cmd == TIOCEXT) {
60847301Sluoqi		/*
60947301Sluoqi		 * When the EXTPROC bit is being toggled, we need
61047301Sluoqi		 * to send an TIOCPKT_IOCTL if the packet driver
61147301Sluoqi		 * is turned on.
61247301Sluoqi		 */
61347301Sluoqi		if (*(int *)data) {
614130263Sphk			if (pt->pt_flags & PF_PKT) {
615130263Sphk				pt->pt_send |= TIOCPKT_IOCTL;
61647301Sluoqi				ptcwakeup(tp, FREAD);
61747301Sluoqi			}
61847301Sluoqi			tp->t_lflag |= EXTPROC;
61947301Sluoqi		} else {
62047301Sluoqi			if ((tp->t_lflag & EXTPROC) &&
621130263Sphk			    (pt->pt_flags & PF_PKT)) {
622130263Sphk				pt->pt_send |= TIOCPKT_IOCTL;
62347301Sluoqi				ptcwakeup(tp, FREAD);
62447301Sluoqi			}
62547301Sluoqi			tp->t_lflag &= ~EXTPROC;
62647301Sluoqi		}
62747301Sluoqi		return(0);
62847301Sluoqi	}
629130054Sphk	error = ttyioctl(dev, cmd, data, flag, td);
630130054Sphk	if (error == ENOTTY) {
631130263Sphk		if (pt->pt_flags & PF_UCNTL &&
6321541Srgrimes		    (cmd & ~0xff) == UIOCCMD(0)) {
6331541Srgrimes			if (cmd & 0xff) {
634130263Sphk				pt->pt_ucntl = (u_char)cmd;
6351541Srgrimes				ptcwakeup(tp, FREAD);
6361541Srgrimes			}
6371541Srgrimes			return (0);
6381541Srgrimes		}
6391541Srgrimes		error = ENOTTY;
6401541Srgrimes	}
6411541Srgrimes	/*
6421541Srgrimes	 * If external processing and packet mode send ioctl packet.
6431541Srgrimes	 */
644130263Sphk	if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) {
6451541Srgrimes		switch(cmd) {
6461541Srgrimes		case TIOCSETA:
6471541Srgrimes		case TIOCSETAW:
6481541Srgrimes		case TIOCSETAF:
649130892Sphk#ifndef BURN_BRIDGES
6501541Srgrimes#ifdef COMPAT_43
6511541Srgrimes		case TIOCSETP:
6521541Srgrimes		case TIOCSETN:
6531541Srgrimes		case TIOCSETC:
6541541Srgrimes		case TIOCSLTC:
6551541Srgrimes		case TIOCLBIS:
6561541Srgrimes		case TIOCLBIC:
6571541Srgrimes		case TIOCLSET:
6581541Srgrimes#endif
659130892Sphk#endif
660130263Sphk			pt->pt_send |= TIOCPKT_IOCTL;
6611541Srgrimes			ptcwakeup(tp, FREAD);
662115463Sphk			break;
6631541Srgrimes		default:
6641541Srgrimes			break;
6651541Srgrimes		}
6661541Srgrimes	}
6678876Srgrimes	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
6681541Srgrimes		&& CCEQ(cc[VSTART], CTRL('q'));
669130263Sphk	if (pt->pt_flags & PF_NOSTOP) {
6701541Srgrimes		if (stop) {
671130263Sphk			pt->pt_send &= ~TIOCPKT_NOSTOP;
672130263Sphk			pt->pt_send |= TIOCPKT_DOSTOP;
673130263Sphk			pt->pt_flags &= ~PF_NOSTOP;
6741541Srgrimes			ptcwakeup(tp, FREAD);
6751541Srgrimes		}
6761541Srgrimes	} else {
6771541Srgrimes		if (!stop) {
678130263Sphk			pt->pt_send &= ~TIOCPKT_DOSTOP;
679130263Sphk			pt->pt_send |= TIOCPKT_NOSTOP;
680130263Sphk			pt->pt_flags |= PF_NOSTOP;
6811541Srgrimes			ptcwakeup(tp, FREAD);
6821541Srgrimes		}
6831541Srgrimes	}
6841541Srgrimes	return (error);
6851541Srgrimes}
68612517Sjulian
68712675Sjulianstatic void
688130585Sphkpty_clone(void *arg, char *name, int namelen, struct cdev **dev)
68964880Sphk{
69064880Sphk	int u;
69164880Sphk
692130640Sphk	if (*dev != NULL)
69364880Sphk		return;
69464880Sphk	if (bcmp(name, "pty", 3) != 0)
69564880Sphk		return;
69664880Sphk	if (name[5] != '\0')
69764880Sphk		return;
69864880Sphk	switch (name[3]) {
69964880Sphk	case 'p': u =   0; break;
70064880Sphk	case 'q': u =  32; break;
70164880Sphk	case 'r': u =  64; break;
70264880Sphk	case 's': u =  96; break;
70364880Sphk	case 'P': u = 128; break;
70464880Sphk	case 'Q': u = 160; break;
70564880Sphk	case 'R': u = 192; break;
70664880Sphk	case 'S': u = 224; break;
70764880Sphk	default: return;
70864880Sphk	}
70964880Sphk	if (name[4] >= '0' && name[4] <= '9')
71064880Sphk		u += name[4] - '0';
71164880Sphk	else if (name[4] >= 'a' && name[4] <= 'v')
71264880Sphk		u += name[4] - 'a' + 10;
71364880Sphk	else
71464880Sphk		return;
71577176Sphk	*dev = make_dev(&ptc_cdevsw, u,
71677176Sphk	    UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32);
71777176Sphk	(*dev)->si_flags |= SI_CHEAPCLONE;
71864880Sphk	return;
71964880Sphk}
72064880Sphk
72164880Sphkstatic void
722130262Sphkptc_drvinit(void *unused)
72312517Sjulian{
724108363Sphk
72565374Sphk	EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000);
72612517Sjulian}
72712517Sjulian
72812517SjulianSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
729