Home | History | Annotate | Line # | Download | only in kern
tty_pty.c revision 1.77
      1  1.77  christos /*	$NetBSD: tty_pty.c,v 1.77 2004/05/27 02:56:38 christos Exp $	*/
      2  1.23       cgd 
      3   1.1       cgd /*
      4  1.22       cgd  * Copyright (c) 1982, 1986, 1989, 1993
      5  1.22       cgd  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1       cgd  * modification, are permitted provided that the following conditions
      9   1.1       cgd  * are met:
     10   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15  1.72       agc  * 3. Neither the name of the University nor the names of its contributors
     16   1.1       cgd  *    may be used to endorse or promote products derived from this software
     17   1.1       cgd  *    without specific prior written permission.
     18   1.1       cgd  *
     19   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29   1.1       cgd  * SUCH DAMAGE.
     30   1.1       cgd  *
     31  1.39      fvdl  *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
     32   1.1       cgd  */
     33   1.1       cgd 
     34   1.1       cgd /*
     35   1.1       cgd  * Pseudo-teletype Driver
     36   1.1       cgd  * (Actually two drivers, requiring two entries in 'cdevsw')
     37  1.77  christos  * Additional multiplexor driver /dev/ptm{,x}
     38   1.1       cgd  */
     39  1.57     lukem 
     40  1.57     lukem #include <sys/cdefs.h>
     41  1.77  christos __KERNEL_RCSID(0, "$NetBSD: tty_pty.c,v 1.77 2004/05/27 02:56:38 christos Exp $");
     42  1.41   thorpej 
     43  1.41   thorpej #include "opt_compat_sunos.h"
     44  1.77  christos #include "pty.h"
     45  1.41   thorpej 
     46  1.16   mycroft #include <sys/param.h>
     47  1.16   mycroft #include <sys/systm.h>
     48  1.16   mycroft #include <sys/ioctl.h>
     49  1.22       cgd #include <sys/proc.h>
     50  1.16   mycroft #include <sys/tty.h>
     51  1.77  christos #include <sys/stat.h>
     52  1.16   mycroft #include <sys/file.h>
     53  1.16   mycroft #include <sys/uio.h>
     54  1.16   mycroft #include <sys/kernel.h>
     55  1.16   mycroft #include <sys/vnode.h>
     56  1.77  christos #include <sys/namei.h>
     57  1.31  christos #include <sys/signalvar.h>
     58  1.31  christos #include <sys/uio.h>
     59  1.77  christos #include <sys/filedesc.h>
     60  1.33  christos #include <sys/conf.h>
     61  1.38   mycroft #include <sys/poll.h>
     62  1.47  jdolecek #include <sys/malloc.h>
     63  1.31  christos 
     64  1.47  jdolecek #define	DEFAULT_NPTYS		16	/* default number of initial ptys */
     65  1.58       tls #define DEFAULT_MAXPTYS		992	/* default maximum number of ptys */
     66   1.1       cgd 
     67  1.77  christos #if 1
     68  1.77  christos #define DPRINTF(a) uprintf a
     69  1.77  christos #else
     70  1.77  christos #define DPRINTF(a)
     71  1.77  christos #endif
     72  1.77  christos 
     73  1.37   mycroft /* Macros to clear/set/test flags. */
     74  1.37   mycroft #define	SET(t, f)	(t) |= (f)
     75  1.37   mycroft #define	CLR(t, f)	(t) &= ~((unsigned)(f))
     76  1.37   mycroft #define	ISSET(t, f)	((t) & (f))
     77  1.37   mycroft 
     78   1.1       cgd #define BUFSIZ 100		/* Chunk size iomoved to/from user */
     79   1.1       cgd 
     80   1.1       cgd /*
     81   1.1       cgd  * pts == /dev/tty[pqrs]?
     82   1.1       cgd  * ptc == /dev/pty[pqrs]?
     83   1.1       cgd  */
     84  1.77  christos 
     85  1.77  christos #define TTY_TEMPLATE	"/dev/XtyXX"
     86  1.77  christos #define TTY_NAMESIZE	sizeof(TTY_TEMPLATE)
     87  1.77  christos /* XXX this needs to come from somewhere sane, and work with MAKEDEV */
     88  1.77  christos #define TTY_LETTERS	"pqrstuvwxyzPQRST"
     89  1.77  christos #define TTY_OLD_SUFFIX  "0123456789abcdef"
     90  1.77  christos #define TTY_NEW_SUFFIX  "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
     91  1.77  christos 
     92  1.27   mycroft struct	pt_softc {
     93  1.27   mycroft 	struct	tty *pt_tty;
     94   1.1       cgd 	int	pt_flags;
     95  1.22       cgd 	struct	selinfo pt_selr, pt_selw;
     96   1.1       cgd 	u_char	pt_send;
     97   1.1       cgd 	u_char	pt_ucntl;
     98  1.47  jdolecek };
     99  1.47  jdolecek 
    100  1.48  jdolecek static struct pt_softc **pt_softc = NULL;	/* pty array */
    101  1.48  jdolecek static int npty = 0;			/* for pstat -t */
    102  1.48  jdolecek static int maxptys = DEFAULT_MAXPTYS;	/* maximum number of ptys (sysctable) */
    103  1.48  jdolecek static struct simplelock pt_softc_mutex = SIMPLELOCK_INITIALIZER;
    104   1.1       cgd 
    105   1.1       cgd #define	PF_PKT		0x08		/* packet mode */
    106   1.1       cgd #define	PF_STOPPED	0x10		/* user told stopped */
    107   1.1       cgd #define	PF_REMOTE	0x20		/* remote and flow controlled input */
    108   1.1       cgd #define	PF_NOSTOP	0x40
    109   1.1       cgd #define PF_UCNTL	0x80		/* user control mode */
    110   1.1       cgd 
    111  1.76  junyoung void	ptyattach(int);
    112  1.76  junyoung void	ptcwakeup(struct tty *, int);
    113  1.76  junyoung void	ptsstart(struct tty *);
    114  1.76  junyoung int	pty_maxptys(int, int);
    115  1.15   deraadt 
    116  1.76  junyoung static struct pt_softc **ptyarralloc(int);
    117  1.71       dsl static int check_pty(int);
    118  1.47  jdolecek 
    119  1.77  christos #ifdef NPTM
    120  1.77  christos 
    121  1.77  christos static int pts_major;
    122  1.77  christos 
    123  1.77  christos static dev_t pty_getfree(void);
    124  1.77  christos static char *pty_makename(char *, dev_t, char);
    125  1.77  christos static int pty_grant_slave(struct proc *, dev_t);
    126  1.77  christos static int pty_alloc_master(struct proc *, int *, dev_t *);
    127  1.77  christos static int pty_alloc_slave(struct proc *, int *, dev_t);
    128  1.77  christos static void pty_fill_ptmget(dev_t, int, int, void *);
    129  1.77  christos 
    130  1.77  christos void ptmattach(int);
    131  1.77  christos 
    132  1.77  christos dev_type_open(ptmopen);
    133  1.77  christos dev_type_close(ptmclose);
    134  1.77  christos dev_type_ioctl(ptmioctl);
    135  1.77  christos 
    136  1.77  christos const struct cdevsw ptm_cdevsw = {
    137  1.77  christos 	ptmopen, ptmclose, noread, nowrite, ptmioctl,
    138  1.77  christos 	nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
    139  1.77  christos };
    140  1.77  christos #endif
    141  1.77  christos 
    142  1.63   gehenna dev_type_open(ptcopen);
    143  1.63   gehenna dev_type_close(ptcclose);
    144  1.63   gehenna dev_type_read(ptcread);
    145  1.63   gehenna dev_type_write(ptcwrite);
    146  1.63   gehenna dev_type_poll(ptcpoll);
    147  1.65  jdolecek dev_type_kqfilter(ptckqfilter);
    148  1.63   gehenna 
    149  1.63   gehenna dev_type_open(ptsopen);
    150  1.63   gehenna dev_type_close(ptsclose);
    151  1.63   gehenna dev_type_read(ptsread);
    152  1.63   gehenna dev_type_write(ptswrite);
    153  1.63   gehenna dev_type_stop(ptsstop);
    154  1.63   gehenna dev_type_poll(ptspoll);
    155  1.63   gehenna 
    156  1.63   gehenna dev_type_ioctl(ptyioctl);
    157  1.63   gehenna dev_type_tty(ptytty);
    158  1.63   gehenna 
    159  1.63   gehenna const struct cdevsw ptc_cdevsw = {
    160  1.63   gehenna 	ptcopen, ptcclose, ptcread, ptcwrite, ptyioctl,
    161  1.65  jdolecek 	nullstop, ptytty, ptcpoll, nommap, ptckqfilter, D_TTY
    162  1.63   gehenna };
    163  1.63   gehenna 
    164  1.63   gehenna const struct cdevsw pts_cdevsw = {
    165  1.63   gehenna 	ptsopen, ptsclose, ptsread, ptswrite, ptyioctl,
    166  1.65  jdolecek 	ptsstop, ptytty, ptspoll, nommap, ttykqfilter, D_TTY
    167  1.63   gehenna };
    168  1.63   gehenna 
    169  1.63   gehenna #if defined(pmax)
    170  1.63   gehenna const struct cdevsw ptc_ultrix_cdevsw = {
    171  1.63   gehenna 	ptcopen, ptcclose, ptcread, ptcwrite, ptyioctl,
    172  1.65  jdolecek 	nullstop, ptytty, ptcpoll, nommap, ptckqfilter, D_TTY
    173  1.63   gehenna };
    174  1.63   gehenna 
    175  1.63   gehenna const struct cdevsw pts_ultrix_cdevsw = {
    176  1.63   gehenna 	ptsopen, ptsclose, ptsread, ptswrite, ptyioctl,
    177  1.65  jdolecek 	ptsstop, ptytty, ptspoll, nommap, ttykqfilter, D_TTY
    178  1.63   gehenna };
    179  1.63   gehenna #endif /* defined(pmax) */
    180  1.63   gehenna 
    181  1.47  jdolecek /*
    182  1.48  jdolecek  * Allocate and zero array of nelem elements.
    183  1.47  jdolecek  */
    184  1.47  jdolecek static struct pt_softc **
    185  1.47  jdolecek ptyarralloc(nelem)
    186  1.47  jdolecek 	int nelem;
    187  1.47  jdolecek {
    188  1.47  jdolecek 	struct pt_softc **pt;
    189  1.47  jdolecek 	nelem += 10;
    190  1.71       dsl 	pt = malloc(nelem * sizeof *pt, M_DEVBUF, M_WAITOK | M_ZERO);
    191  1.47  jdolecek 	return pt;
    192  1.47  jdolecek }
    193  1.47  jdolecek 
    194  1.47  jdolecek /*
    195  1.47  jdolecek  * Check if the minor is correct and ensure necessary structures
    196  1.47  jdolecek  * are properly allocated.
    197  1.47  jdolecek  */
    198  1.47  jdolecek static int
    199  1.71       dsl check_pty(int ptn)
    200  1.47  jdolecek {
    201  1.47  jdolecek 	struct pt_softc *pti;
    202  1.47  jdolecek 
    203  1.71       dsl 	if (ptn >= npty) {
    204  1.71       dsl 		struct pt_softc **newpt, **oldpt;
    205  1.48  jdolecek 		int newnpty;
    206  1.47  jdolecek 
    207  1.48  jdolecek 		/* check if the requested pty can be granted */
    208  1.71       dsl 		if (ptn >= maxptys) {
    209  1.48  jdolecek 	    limit_reached:
    210  1.48  jdolecek 			tablefull("pty", "increase kern.maxptys");
    211  1.48  jdolecek 			return (ENXIO);
    212  1.48  jdolecek 		}
    213  1.47  jdolecek 
    214  1.71       dsl 		/* Allocate a larger pty array */
    215  1.71       dsl 		for (newnpty = npty; newnpty <= ptn;)
    216  1.71       dsl 			newnpty *= 2;
    217  1.71       dsl 		if (newnpty > maxptys)
    218  1.71       dsl 			newnpty = maxptys;
    219  1.71       dsl 		newpt = ptyarralloc(newnpty);
    220  1.71       dsl 
    221  1.47  jdolecek 		/*
    222  1.48  jdolecek 		 * Now grab the pty array mutex - we need to ensure
    223  1.47  jdolecek 		 * that the pty array is consistent while copying it's
    224  1.48  jdolecek 		 * content to newly allocated, larger space; we also
    225  1.48  jdolecek 		 * need to be safe against pty_maxptys().
    226  1.47  jdolecek 		 */
    227  1.48  jdolecek 		simple_lock(&pt_softc_mutex);
    228  1.48  jdolecek 
    229  1.71       dsl 		if (newnpty >= maxptys) {
    230  1.71       dsl 			/* limit cut away beneath us... */
    231  1.71       dsl 			newnpty = maxptys;
    232  1.71       dsl 			if (ptn >= newnpty) {
    233  1.54     enami 				simple_unlock(&pt_softc_mutex);
    234  1.71       dsl 				free(newpt, M_DEVBUF);
    235  1.48  jdolecek 				goto limit_reached;
    236  1.48  jdolecek 			}
    237  1.71       dsl 		}
    238  1.47  jdolecek 
    239  1.47  jdolecek 		/*
    240  1.48  jdolecek 		 * If the pty array was not enlarged while we were waiting
    241  1.48  jdolecek 		 * for mutex, copy current contents of pt_softc[] to newly
    242  1.48  jdolecek 		 * allocated array and start using the new bigger array.
    243  1.47  jdolecek 		 */
    244  1.71       dsl 		if (newnpty > npty) {
    245  1.47  jdolecek 			memcpy(newpt, pt_softc, npty*sizeof(struct pt_softc *));
    246  1.71       dsl 			oldpt = pt_softc;
    247  1.47  jdolecek 			pt_softc = newpt;
    248  1.47  jdolecek 			npty = newnpty;
    249  1.47  jdolecek 		} else {
    250  1.71       dsl 			/* was enlarged when waited for lock, free new space */
    251  1.71       dsl 			oldpt = newpt;
    252  1.47  jdolecek 		}
    253  1.48  jdolecek 
    254  1.48  jdolecek 		simple_unlock(&pt_softc_mutex);
    255  1.71       dsl 		free(oldpt, M_DEVBUF);
    256  1.47  jdolecek 	}
    257  1.71       dsl 
    258  1.47  jdolecek 	/*
    259  1.48  jdolecek 	 * If the entry is not yet allocated, allocate one. The mutex is
    260  1.48  jdolecek 	 * needed so that the state of pt_softc[] array is consistant
    261  1.71       dsl 	 * in case it has been lengthened above.
    262  1.47  jdolecek 	 */
    263  1.71       dsl 	if (!pt_softc[ptn]) {
    264  1.48  jdolecek 		MALLOC(pti, struct pt_softc *, sizeof(struct pt_softc),
    265  1.48  jdolecek 			M_DEVBUF, M_WAITOK);
    266  1.64  jdolecek 		memset(pti, 0, sizeof(struct pt_softc));
    267  1.48  jdolecek 
    268  1.48  jdolecek 	 	pti->pt_tty = ttymalloc();
    269  1.48  jdolecek 
    270  1.48  jdolecek 		simple_lock(&pt_softc_mutex);
    271  1.47  jdolecek 
    272  1.47  jdolecek 		/*
    273  1.48  jdolecek 		 * Check the entry again - it might have been
    274  1.48  jdolecek 		 * added while we were waiting for mutex.
    275  1.47  jdolecek 		 */
    276  1.71       dsl 		if (!pt_softc[ptn]) {
    277  1.47  jdolecek 			tty_attach(pti->pt_tty);
    278  1.71       dsl 			pt_softc[ptn] = pti;
    279  1.48  jdolecek 		} else {
    280  1.48  jdolecek 			ttyfree(pti->pt_tty);
    281  1.71       dsl 			free(pti, M_DEVBUF);
    282  1.47  jdolecek 		}
    283  1.48  jdolecek 
    284  1.48  jdolecek 		simple_unlock(&pt_softc_mutex);
    285  1.48  jdolecek 	}
    286  1.48  jdolecek 
    287  1.48  jdolecek 	return (0);
    288  1.48  jdolecek }
    289  1.48  jdolecek 
    290  1.48  jdolecek /*
    291  1.48  jdolecek  * Set maxpty in thread-safe way. Returns 0 in case of error, otherwise
    292  1.48  jdolecek  * new value of maxptys.
    293  1.48  jdolecek  */
    294  1.48  jdolecek int
    295  1.48  jdolecek pty_maxptys(newmax, set)
    296  1.48  jdolecek 	int newmax, set;
    297  1.48  jdolecek {
    298  1.48  jdolecek 	if (!set)
    299  1.48  jdolecek 		return (maxptys);
    300  1.48  jdolecek 
    301  1.48  jdolecek 	/*
    302  1.48  jdolecek 	 * We have to grab the pt_softc lock, so that we would pick correct
    303  1.48  jdolecek 	 * value of npty (might be modified in check_pty()).
    304  1.48  jdolecek 	 */
    305  1.48  jdolecek 	simple_lock(&pt_softc_mutex);
    306  1.48  jdolecek 
    307  1.71       dsl 	/*
    308  1.71       dsl 	 * The value cannot be set to value lower than the highest pty
    309  1.71       dsl 	 * number ever allocated.
    310  1.71       dsl 	 */
    311  1.71       dsl 	if (newmax >= npty)
    312  1.48  jdolecek 		maxptys = newmax;
    313  1.71       dsl 	else
    314  1.71       dsl 		newmax = 0;
    315  1.47  jdolecek 
    316  1.48  jdolecek 	simple_unlock(&pt_softc_mutex);
    317  1.48  jdolecek 
    318  1.71       dsl 	return newmax;
    319  1.47  jdolecek }
    320  1.47  jdolecek 
    321  1.22       cgd /*
    322  1.22       cgd  * Establish n (or default if n is 1) ptys in the system.
    323  1.22       cgd  */
    324  1.15   deraadt void
    325  1.15   deraadt ptyattach(n)
    326  1.15   deraadt 	int n;
    327  1.15   deraadt {
    328  1.22       cgd 	/* maybe should allow 0 => none? */
    329  1.22       cgd 	if (n <= 1)
    330  1.47  jdolecek 		n = DEFAULT_NPTYS;
    331  1.47  jdolecek 	pt_softc = ptyarralloc(n);
    332  1.22       cgd 	npty = n;
    333  1.15   deraadt }
    334   1.7    andrew 
    335   1.1       cgd /*ARGSUSED*/
    336  1.31  christos int
    337  1.70      fvdl ptsopen(dev, flag, devtype, p)
    338   1.1       cgd 	dev_t dev;
    339   1.7    andrew 	int flag, devtype;
    340  1.70      fvdl 	struct proc *p;
    341   1.1       cgd {
    342  1.27   mycroft 	struct pt_softc *pti;
    343  1.43  augustss 	struct tty *tp;
    344   1.1       cgd 	int error;
    345  1.71       dsl 	int ptn = minor(dev);
    346  1.75       dbj 	int s;
    347   1.1       cgd 
    348  1.71       dsl 	if ((error = check_pty(ptn)))
    349  1.47  jdolecek 		return (error);
    350  1.47  jdolecek 
    351  1.71       dsl 	pti = pt_softc[ptn];
    352  1.47  jdolecek 	tp = pti->pt_tty;
    353  1.47  jdolecek 
    354  1.37   mycroft 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
    355   1.1       cgd 		ttychars(tp);		/* Set up default chars */
    356   1.1       cgd 		tp->t_iflag = TTYDEF_IFLAG;
    357   1.1       cgd 		tp->t_oflag = TTYDEF_OFLAG;
    358   1.1       cgd 		tp->t_lflag = TTYDEF_LFLAG;
    359   1.1       cgd 		tp->t_cflag = TTYDEF_CFLAG;
    360   1.1       cgd 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
    361   1.1       cgd 		ttsetwater(tp);		/* would be done in xxparam() */
    362  1.37   mycroft 	} else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
    363   1.1       cgd 		return (EBUSY);
    364   1.1       cgd 	if (tp->t_oproc)			/* Ctrlr still around. */
    365  1.37   mycroft 		SET(tp->t_state, TS_CARR_ON);
    366  1.71       dsl 
    367  1.68        pk 	if (!ISSET(flag, O_NONBLOCK)) {
    368  1.75       dbj 		s = spltty();
    369  1.68        pk 		TTY_LOCK(tp);
    370  1.40   mycroft 		while (!ISSET(tp->t_state, TS_CARR_ON)) {
    371  1.40   mycroft 			tp->t_wopen++;
    372  1.40   mycroft 			error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
    373  1.40   mycroft 			    ttopen, 0);
    374  1.40   mycroft 			tp->t_wopen--;
    375  1.68        pk 			if (error) {
    376  1.68        pk 				TTY_UNLOCK(tp);
    377  1.75       dbj 				splx(s);
    378  1.40   mycroft 				return (error);
    379  1.68        pk 			}
    380  1.40   mycroft 		}
    381  1.68        pk 		TTY_UNLOCK(tp);
    382  1.75       dbj 		splx(s);
    383  1.68        pk 	}
    384  1.50       eeh 	error = (*tp->t_linesw->l_open)(dev, tp);
    385   1.1       cgd 	ptcwakeup(tp, FREAD|FWRITE);
    386  1.22       cgd 	return (error);
    387   1.1       cgd }
    388   1.1       cgd 
    389  1.31  christos int
    390  1.70      fvdl ptsclose(dev, flag, mode, p)
    391   1.1       cgd 	dev_t dev;
    392   1.1       cgd 	int flag, mode;
    393  1.70      fvdl 	struct proc *p;
    394   1.1       cgd {
    395  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    396  1.43  augustss 	struct tty *tp = pti->pt_tty;
    397  1.31  christos 	int error;
    398   1.1       cgd 
    399  1.50       eeh 	error = (*tp->t_linesw->l_close)(tp, flag);
    400  1.31  christos 	error |= ttyclose(tp);
    401   1.1       cgd 	ptcwakeup(tp, FREAD|FWRITE);
    402  1.31  christos 	return (error);
    403   1.1       cgd }
    404   1.1       cgd 
    405  1.31  christos int
    406   1.1       cgd ptsread(dev, uio, flag)
    407   1.1       cgd 	dev_t dev;
    408   1.1       cgd 	struct uio *uio;
    409   1.7    andrew 	int flag;
    410   1.1       cgd {
    411   1.1       cgd 	struct proc *p = curproc;
    412  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    413  1.43  augustss 	struct tty *tp = pti->pt_tty;
    414   1.1       cgd 	int error = 0;
    415  1.68        pk 	int cc;
    416  1.75       dbj 	int s;
    417   1.1       cgd 
    418   1.1       cgd again:
    419   1.1       cgd 	if (pti->pt_flags & PF_REMOTE) {
    420   1.1       cgd 		while (isbackground(p, tp)) {
    421  1.51  jdolecek 			if (sigismasked(p, SIGTTIN) ||
    422   1.1       cgd 			    p->p_pgrp->pg_jobc == 0 ||
    423  1.22       cgd 			    p->p_flag & P_PPWAIT)
    424   1.1       cgd 				return (EIO);
    425   1.1       cgd 			pgsignal(p->p_pgrp, SIGTTIN, 1);
    426  1.75       dbj 			s = spltty();
    427  1.68        pk 			TTY_LOCK(tp);
    428  1.35        pk 			error = ttysleep(tp, (caddr_t)&lbolt,
    429  1.68        pk 					 TTIPRI | PCATCH | PNORELOCK, ttybg, 0);
    430  1.75       dbj 			splx(s);
    431  1.31  christos 			if (error)
    432   1.1       cgd 				return (error);
    433   1.1       cgd 		}
    434  1.75       dbj 		s = spltty();
    435  1.68        pk 		TTY_LOCK(tp);
    436   1.8   mycroft 		if (tp->t_canq.c_cc == 0) {
    437  1.68        pk 			if (flag & IO_NDELAY) {
    438  1.68        pk 				TTY_UNLOCK(tp);
    439  1.75       dbj 				splx(s);
    440   1.1       cgd 				return (EWOULDBLOCK);
    441  1.68        pk 			}
    442  1.31  christos 			error = ttysleep(tp, (caddr_t)&tp->t_canq,
    443  1.68        pk 					 TTIPRI | PCATCH | PNORELOCK, ttyin, 0);
    444  1.31  christos 			if (error)
    445   1.1       cgd 				return (error);
    446   1.1       cgd 			goto again;
    447   1.1       cgd 		}
    448  1.68        pk 		while(error == 0 && tp->t_canq.c_cc > 1 && uio->uio_resid > 0) {
    449  1.68        pk 			TTY_UNLOCK(tp);
    450  1.75       dbj 			splx(s);
    451  1.68        pk 			error = ureadc(getc(&tp->t_canq), uio);
    452  1.75       dbj 			s = spltty();
    453  1.68        pk 			TTY_LOCK(tp);
    454  1.68        pk 			/* Re-check terminal state here? */
    455  1.68        pk 		}
    456   1.8   mycroft 		if (tp->t_canq.c_cc == 1)
    457   1.8   mycroft 			(void) getc(&tp->t_canq);
    458  1.68        pk 		cc = tp->t_canq.c_cc;
    459  1.68        pk 		TTY_UNLOCK(tp);
    460  1.75       dbj 		splx(s);
    461  1.68        pk 		if (cc)
    462   1.1       cgd 			return (error);
    463   1.1       cgd 	} else
    464   1.1       cgd 		if (tp->t_oproc)
    465  1.50       eeh 			error = (*tp->t_linesw->l_read)(tp, uio, flag);
    466   1.1       cgd 	ptcwakeup(tp, FWRITE);
    467   1.1       cgd 	return (error);
    468   1.1       cgd }
    469   1.1       cgd 
    470   1.1       cgd /*
    471   1.1       cgd  * Write to pseudo-tty.
    472   1.1       cgd  * Wakeups of controlling tty will happen
    473   1.1       cgd  * indirectly, when tty driver calls ptsstart.
    474   1.1       cgd  */
    475  1.31  christos int
    476   1.1       cgd ptswrite(dev, uio, flag)
    477   1.1       cgd 	dev_t dev;
    478   1.1       cgd 	struct uio *uio;
    479   1.7    andrew 	int flag;
    480   1.1       cgd {
    481  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    482  1.43  augustss 	struct tty *tp = pti->pt_tty;
    483   1.1       cgd 
    484   1.1       cgd 	if (tp->t_oproc == 0)
    485   1.1       cgd 		return (EIO);
    486  1.50       eeh 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
    487  1.56       scw }
    488  1.56       scw 
    489  1.56       scw /*
    490  1.56       scw  * Poll pseudo-tty.
    491  1.56       scw  */
    492  1.56       scw int
    493  1.70      fvdl ptspoll(dev, events, p)
    494  1.56       scw 	dev_t dev;
    495  1.56       scw 	int events;
    496  1.70      fvdl 	struct proc *p;
    497  1.56       scw {
    498  1.56       scw 	struct pt_softc *pti = pt_softc[minor(dev)];
    499  1.56       scw 	struct tty *tp = pti->pt_tty;
    500  1.56       scw 
    501  1.56       scw 	if (tp->t_oproc == 0)
    502  1.56       scw 		return (EIO);
    503  1.56       scw 
    504  1.70      fvdl 	return ((*tp->t_linesw->l_poll)(tp, events, p));
    505   1.1       cgd }
    506   1.1       cgd 
    507   1.1       cgd /*
    508   1.1       cgd  * Start output on pseudo-tty.
    509  1.38   mycroft  * Wake up process polling or sleeping for input from controlling tty.
    510  1.68        pk  * Called with tty slock held.
    511   1.1       cgd  */
    512  1.12   deraadt void
    513   1.1       cgd ptsstart(tp)
    514   1.1       cgd 	struct tty *tp;
    515   1.1       cgd {
    516  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
    517   1.1       cgd 
    518  1.37   mycroft 	if (ISSET(tp->t_state, TS_TTSTOP))
    519  1.12   deraadt 		return;
    520   1.1       cgd 	if (pti->pt_flags & PF_STOPPED) {
    521   1.1       cgd 		pti->pt_flags &= ~PF_STOPPED;
    522   1.1       cgd 		pti->pt_send = TIOCPKT_START;
    523   1.1       cgd 	}
    524  1.68        pk 
    525  1.73  jdolecek 	selnotify(&pti->pt_selr, NOTE_SUBMIT);
    526  1.68        pk 	wakeup((caddr_t)&tp->t_outq.c_cf);
    527   1.1       cgd }
    528   1.1       cgd 
    529  1.68        pk /*
    530  1.68        pk  * Stop output.
    531  1.68        pk  * Called with tty slock held.
    532  1.68        pk  */
    533  1.36   mycroft void
    534  1.31  christos ptsstop(tp, flush)
    535  1.43  augustss 	struct tty *tp;
    536  1.31  christos 	int flush;
    537  1.31  christos {
    538  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
    539  1.31  christos 
    540  1.31  christos 	/* note: FLUSHREAD and FLUSHWRITE already ok */
    541  1.31  christos 	if (flush == 0) {
    542  1.31  christos 		flush = TIOCPKT_STOP;
    543  1.31  christos 		pti->pt_flags |= PF_STOPPED;
    544  1.31  christos 	} else
    545  1.31  christos 		pti->pt_flags &= ~PF_STOPPED;
    546  1.31  christos 	pti->pt_send |= flush;
    547  1.68        pk 
    548  1.31  christos 	/* change of perspective */
    549  1.68        pk 	if (flush & FREAD) {
    550  1.73  jdolecek 		selnotify(&pti->pt_selw, NOTE_SUBMIT);
    551  1.68        pk 		wakeup((caddr_t)&tp->t_rawq.c_cf);
    552  1.68        pk 	}
    553  1.68        pk 	if (flush & FWRITE) {
    554  1.73  jdolecek 		selnotify(&pti->pt_selr, NOTE_SUBMIT);
    555  1.68        pk 		wakeup((caddr_t)&tp->t_outq.c_cf);
    556  1.68        pk 	}
    557  1.31  christos }
    558  1.31  christos 
    559  1.31  christos void
    560   1.1       cgd ptcwakeup(tp, flag)
    561   1.1       cgd 	struct tty *tp;
    562   1.7    andrew 	int flag;
    563   1.1       cgd {
    564  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
    565  1.74       dbj 	int s;
    566   1.1       cgd 
    567  1.74       dbj 	s = spltty();
    568  1.68        pk 	TTY_LOCK(tp);
    569   1.1       cgd 	if (flag & FREAD) {
    570  1.73  jdolecek 		selnotify(&pti->pt_selr, NOTE_SUBMIT);
    571  1.22       cgd 		wakeup((caddr_t)&tp->t_outq.c_cf);
    572   1.1       cgd 	}
    573   1.1       cgd 	if (flag & FWRITE) {
    574  1.73  jdolecek 		selnotify(&pti->pt_selw, NOTE_SUBMIT);
    575   1.8   mycroft 		wakeup((caddr_t)&tp->t_rawq.c_cf);
    576   1.1       cgd 	}
    577  1.68        pk 	TTY_UNLOCK(tp);
    578  1.74       dbj 	splx(s);
    579   1.1       cgd }
    580   1.1       cgd 
    581   1.1       cgd /*ARGSUSED*/
    582  1.25   mycroft int
    583  1.70      fvdl ptcopen(dev, flag, devtype, p)
    584   1.1       cgd 	dev_t dev;
    585   1.1       cgd 	int flag, devtype;
    586  1.70      fvdl 	struct proc *p;
    587   1.1       cgd {
    588  1.27   mycroft 	struct pt_softc *pti;
    589  1.43  augustss 	struct tty *tp;
    590  1.47  jdolecek 	int error;
    591  1.71       dsl 	int ptn = minor(dev);
    592  1.75       dbj 	int s;
    593  1.47  jdolecek 
    594  1.71       dsl 	if ((error = check_pty(ptn)))
    595  1.47  jdolecek 		return (error);
    596  1.47  jdolecek 
    597  1.71       dsl 	pti = pt_softc[ptn];
    598  1.47  jdolecek 	tp = pti->pt_tty;
    599   1.1       cgd 
    600  1.75       dbj 	s = spltty();
    601  1.71       dsl 	TTY_LOCK(tp);
    602  1.71       dsl 	if (tp->t_oproc) {
    603  1.71       dsl 		TTY_UNLOCK(tp);
    604  1.75       dbj 		splx(s);
    605   1.1       cgd 		return (EIO);
    606  1.71       dsl 	}
    607   1.1       cgd 	tp->t_oproc = ptsstart;
    608  1.71       dsl 	TTY_UNLOCK(tp);
    609  1.75       dbj 	splx(s);
    610  1.50       eeh 	(void)(*tp->t_linesw->l_modem)(tp, 1);
    611  1.37   mycroft 	CLR(tp->t_lflag, EXTPROC);
    612  1.22       cgd 	pti->pt_flags = 0;
    613   1.1       cgd 	pti->pt_send = 0;
    614   1.1       cgd 	pti->pt_ucntl = 0;
    615   1.1       cgd 	return (0);
    616   1.1       cgd }
    617   1.1       cgd 
    618  1.31  christos /*ARGSUSED*/
    619  1.25   mycroft int
    620  1.70      fvdl ptcclose(dev, flag, devtype, p)
    621   1.1       cgd 	dev_t dev;
    622  1.31  christos 	int flag, devtype;
    623  1.70      fvdl 	struct proc *p;
    624   1.1       cgd {
    625  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    626  1.43  augustss 	struct tty *tp = pti->pt_tty;
    627  1.75       dbj 	int s;
    628   1.1       cgd 
    629  1.50       eeh 	(void)(*tp->t_linesw->l_modem)(tp, 0);
    630  1.37   mycroft 	CLR(tp->t_state, TS_CARR_ON);
    631  1.75       dbj 	s = spltty();
    632  1.71       dsl 	TTY_LOCK(tp);
    633   1.1       cgd 	tp->t_oproc = 0;		/* mark closed */
    634  1.71       dsl 	TTY_UNLOCK(tp);
    635  1.75       dbj 	splx(s);
    636   1.2       cgd 	return (0);
    637   1.1       cgd }
    638   1.1       cgd 
    639  1.31  christos int
    640   1.1       cgd ptcread(dev, uio, flag)
    641   1.1       cgd 	dev_t dev;
    642   1.1       cgd 	struct uio *uio;
    643   1.7    andrew 	int flag;
    644   1.1       cgd {
    645  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    646  1.43  augustss 	struct tty *tp = pti->pt_tty;
    647  1.67    simonb 	u_char buf[BUFSIZ];
    648   1.1       cgd 	int error = 0, cc;
    649  1.75       dbj 	int s;
    650   1.1       cgd 
    651   1.1       cgd 	/*
    652   1.1       cgd 	 * We want to block until the slave
    653   1.1       cgd 	 * is open, and there's something to read;
    654   1.1       cgd 	 * but if we lost the slave or we're NBIO,
    655   1.1       cgd 	 * then return the appropriate error instead.
    656   1.1       cgd 	 */
    657  1.75       dbj 	s = spltty();
    658  1.68        pk 	TTY_LOCK(tp);
    659   1.1       cgd 	for (;;) {
    660  1.37   mycroft 		if (ISSET(tp->t_state, TS_ISOPEN)) {
    661  1.71       dsl 			if (pti->pt_flags & PF_PKT && pti->pt_send) {
    662  1.68        pk 				TTY_UNLOCK(tp);
    663  1.75       dbj 				splx(s);
    664   1.1       cgd 				error = ureadc((int)pti->pt_send, uio);
    665   1.1       cgd 				if (error)
    666   1.1       cgd 					return (error);
    667  1.68        pk 				/*
    668  1.68        pk 				 * Since we don't have the tty locked, there's
    669  1.68        pk 				 * a risk of messing up `t_termios'. This is
    670  1.68        pk 				 * relevant only if the tty got closed and then
    671  1.68        pk 				 * opened again while we were out uiomoving.
    672  1.68        pk 				 */
    673   1.1       cgd 				if (pti->pt_send & TIOCPKT_IOCTL) {
    674  1.22       cgd 					cc = min(uio->uio_resid,
    675   1.1       cgd 						sizeof(tp->t_termios));
    676  1.31  christos 					uiomove((caddr_t) &tp->t_termios,
    677  1.31  christos 						cc, uio);
    678   1.1       cgd 				}
    679   1.1       cgd 				pti->pt_send = 0;
    680   1.1       cgd 				return (0);
    681   1.1       cgd 			}
    682  1.71       dsl 			if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
    683  1.68        pk 				TTY_UNLOCK(tp);
    684  1.75       dbj 				splx(s);
    685   1.1       cgd 				error = ureadc((int)pti->pt_ucntl, uio);
    686   1.1       cgd 				if (error)
    687   1.1       cgd 					return (error);
    688   1.1       cgd 				pti->pt_ucntl = 0;
    689   1.1       cgd 				return (0);
    690   1.1       cgd 			}
    691  1.37   mycroft 			if (tp->t_outq.c_cc && !ISSET(tp->t_state, TS_TTSTOP))
    692   1.1       cgd 				break;
    693   1.1       cgd 		}
    694  1.68        pk 		if (!ISSET(tp->t_state, TS_CARR_ON)) {
    695  1.68        pk 			error = 0;	/* EOF */
    696  1.68        pk 			goto out;
    697  1.68        pk 		}
    698  1.68        pk 		if (flag & IO_NDELAY) {
    699  1.68        pk 			error = EWOULDBLOCK;
    700  1.68        pk 			goto out;
    701  1.68        pk 		}
    702  1.68        pk 		error = ltsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
    703  1.68        pk 				ttyin, 0, &tp->t_slock);
    704  1.31  christos 		if (error)
    705  1.68        pk 			goto out;
    706   1.1       cgd 	}
    707  1.68        pk 
    708  1.68        pk 	if (pti->pt_flags & (PF_PKT|PF_UCNTL)) {
    709  1.68        pk 		TTY_UNLOCK(tp);
    710  1.75       dbj 		splx(s);
    711   1.1       cgd 		error = ureadc(0, uio);
    712  1.75       dbj 		s = spltty();
    713  1.68        pk 		TTY_LOCK(tp);
    714  1.68        pk 		if (error == 0 && !ISSET(tp->t_state, TS_ISOPEN))
    715  1.68        pk 			error = EIO;
    716  1.68        pk 	}
    717   1.1       cgd 	while (uio->uio_resid > 0 && error == 0) {
    718  1.22       cgd 		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
    719   1.1       cgd 		if (cc <= 0)
    720   1.1       cgd 			break;
    721  1.68        pk 		TTY_UNLOCK(tp);
    722  1.75       dbj 		splx(s);
    723   1.1       cgd 		error = uiomove(buf, cc, uio);
    724  1.75       dbj 		s = spltty();
    725  1.68        pk 		TTY_LOCK(tp);
    726  1.68        pk 		if (error == 0 && !ISSET(tp->t_state, TS_ISOPEN))
    727  1.68        pk 			error = EIO;
    728   1.1       cgd 	}
    729  1.68        pk 
    730   1.8   mycroft 	if (tp->t_outq.c_cc <= tp->t_lowat) {
    731  1.37   mycroft 		if (ISSET(tp->t_state, TS_ASLEEP)) {
    732  1.37   mycroft 			CLR(tp->t_state, TS_ASLEEP);
    733   1.8   mycroft 			wakeup((caddr_t)&tp->t_outq);
    734   1.1       cgd 		}
    735  1.73  jdolecek 		selnotify(&tp->t_wsel, NOTE_SUBMIT);
    736   1.1       cgd 	}
    737  1.68        pk out:
    738  1.68        pk 	TTY_UNLOCK(tp);
    739  1.75       dbj 	splx(s);
    740   1.1       cgd 	return (error);
    741   1.1       cgd }
    742   1.1       cgd 
    743   1.1       cgd 
    744  1.31  christos int
    745   1.1       cgd ptcwrite(dev, uio, flag)
    746   1.1       cgd 	dev_t dev;
    747  1.43  augustss 	struct uio *uio;
    748   1.7    andrew 	int flag;
    749   1.1       cgd {
    750  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    751  1.43  augustss 	struct tty *tp = pti->pt_tty;
    752  1.43  augustss 	u_char *cp = NULL;
    753  1.43  augustss 	int cc = 0;
    754   1.1       cgd 	u_char locbuf[BUFSIZ];
    755   1.1       cgd 	int cnt = 0;
    756   1.1       cgd 	int error = 0;
    757  1.75       dbj 	int s;
    758   1.1       cgd 
    759   1.1       cgd again:
    760  1.75       dbj 	s = spltty();
    761  1.68        pk 	TTY_LOCK(tp);
    762  1.37   mycroft 	if (!ISSET(tp->t_state, TS_ISOPEN))
    763   1.1       cgd 		goto block;
    764   1.1       cgd 	if (pti->pt_flags & PF_REMOTE) {
    765   1.8   mycroft 		if (tp->t_canq.c_cc)
    766   1.1       cgd 			goto block;
    767   1.8   mycroft 		while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
    768   1.1       cgd 			if (cc == 0) {
    769   1.1       cgd 				cc = min(uio->uio_resid, BUFSIZ);
    770   1.8   mycroft 				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
    771   1.1       cgd 				cp = locbuf;
    772  1.68        pk 				TTY_UNLOCK(tp);
    773  1.75       dbj 				splx(s);
    774   1.1       cgd 				error = uiomove((caddr_t)cp, cc, uio);
    775   1.1       cgd 				if (error)
    776   1.1       cgd 					return (error);
    777  1.75       dbj 				s = spltty();
    778  1.68        pk 				TTY_LOCK(tp);
    779   1.1       cgd 				/* check again for safety */
    780  1.68        pk 				if (!ISSET(tp->t_state, TS_ISOPEN)) {
    781  1.68        pk 					error = EIO;
    782  1.68        pk 					goto out;
    783  1.68        pk 				}
    784   1.1       cgd 			}
    785   1.1       cgd 			if (cc)
    786  1.67    simonb 				(void) b_to_q(cp, cc, &tp->t_canq);
    787   1.1       cgd 			cc = 0;
    788   1.1       cgd 		}
    789   1.8   mycroft 		(void) putc(0, &tp->t_canq);
    790   1.1       cgd 		ttwakeup(tp);
    791   1.8   mycroft 		wakeup((caddr_t)&tp->t_canq);
    792  1.68        pk 		error = 0;
    793  1.68        pk 		goto out;
    794   1.1       cgd 	}
    795   1.1       cgd 	while (uio->uio_resid > 0) {
    796   1.1       cgd 		if (cc == 0) {
    797   1.1       cgd 			cc = min(uio->uio_resid, BUFSIZ);
    798   1.1       cgd 			cp = locbuf;
    799  1.68        pk 			TTY_UNLOCK(tp);
    800  1.75       dbj 			splx(s);
    801   1.1       cgd 			error = uiomove((caddr_t)cp, cc, uio);
    802   1.1       cgd 			if (error)
    803   1.1       cgd 				return (error);
    804  1.75       dbj 			s = spltty();
    805  1.68        pk 			TTY_LOCK(tp);
    806   1.1       cgd 			/* check again for safety */
    807  1.68        pk 			if (!ISSET(tp->t_state, TS_ISOPEN)) {
    808  1.68        pk 				error = EIO;
    809  1.68        pk 				goto out;
    810  1.68        pk 			}
    811   1.1       cgd 		}
    812   1.1       cgd 		while (cc > 0) {
    813   1.8   mycroft 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
    814  1.59  christos 			   (tp->t_canq.c_cc > 0 || !ISSET(tp->t_lflag, ICANON))) {
    815   1.8   mycroft 				wakeup((caddr_t)&tp->t_rawq);
    816   1.1       cgd 				goto block;
    817   1.1       cgd 			}
    818  1.68        pk 			/* XXX - should change l_rint to be called with lock
    819  1.68        pk 			 *	 see also tty.c:ttyinput_wlock()
    820  1.68        pk 			 */
    821  1.68        pk 			TTY_UNLOCK(tp);
    822  1.75       dbj 			splx(s);
    823  1.50       eeh 			(*tp->t_linesw->l_rint)(*cp++, tp);
    824  1.75       dbj 			s = spltty();
    825  1.68        pk 			TTY_LOCK(tp);
    826   1.1       cgd 			cnt++;
    827   1.1       cgd 			cc--;
    828   1.1       cgd 		}
    829   1.1       cgd 		cc = 0;
    830   1.1       cgd 	}
    831  1.68        pk 	error = 0;
    832  1.68        pk 	goto out;
    833  1.68        pk 
    834   1.1       cgd block:
    835   1.1       cgd 	/*
    836   1.1       cgd 	 * Come here to wait for slave to open, for space
    837   1.1       cgd 	 * in outq, or space in rawq.
    838   1.1       cgd 	 */
    839  1.68        pk 	if (!ISSET(tp->t_state, TS_CARR_ON)) {
    840  1.68        pk 		error = EIO;
    841  1.68        pk 		goto out;
    842  1.68        pk 	}
    843   1.1       cgd 	if (flag & IO_NDELAY) {
    844   1.1       cgd 		/* adjust for data copied in but not written */
    845   1.1       cgd 		uio->uio_resid += cc;
    846  1.68        pk 		error = cnt == 0 ? EWOULDBLOCK : 0;
    847  1.68        pk 		goto out;
    848   1.1       cgd 	}
    849  1.68        pk 	error = ltsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH | PNORELOCK,
    850  1.68        pk 		       ttyout, 0, &tp->t_slock);
    851  1.75       dbj 	splx(s);
    852  1.31  christos 	if (error) {
    853   1.1       cgd 		/* adjust for data copied in but not written */
    854   1.1       cgd 		uio->uio_resid += cc;
    855   1.1       cgd 		return (error);
    856   1.1       cgd 	}
    857   1.1       cgd 	goto again;
    858  1.68        pk 
    859  1.68        pk out:
    860  1.68        pk 	TTY_UNLOCK(tp);
    861  1.75       dbj 	splx(s);
    862  1.68        pk 	return (error);
    863  1.29   mycroft }
    864  1.29   mycroft 
    865  1.31  christos int
    866  1.70      fvdl ptcpoll(dev, events, p)
    867  1.31  christos 	dev_t dev;
    868  1.38   mycroft 	int events;
    869  1.70      fvdl 	struct proc *p;
    870  1.31  christos {
    871  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
    872  1.43  augustss 	struct tty *tp = pti->pt_tty;
    873  1.38   mycroft 	int revents = 0;
    874  1.38   mycroft 	int s = splsoftclock();
    875  1.31  christos 
    876  1.38   mycroft 	if (events & (POLLIN | POLLRDNORM))
    877  1.37   mycroft 		if (ISSET(tp->t_state, TS_ISOPEN) &&
    878  1.38   mycroft 		    ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
    879  1.38   mycroft 		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
    880  1.38   mycroft 		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
    881  1.38   mycroft 			revents |= events & (POLLIN | POLLRDNORM);
    882  1.31  christos 
    883  1.38   mycroft 	if (events & (POLLOUT | POLLWRNORM))
    884  1.37   mycroft 		if (ISSET(tp->t_state, TS_ISOPEN) &&
    885  1.38   mycroft 		    ((pti->pt_flags & PF_REMOTE) ?
    886  1.38   mycroft 		     (tp->t_canq.c_cc == 0) :
    887  1.38   mycroft 		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
    888  1.59  christos 		      (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))))
    889  1.38   mycroft 			revents |= events & (POLLOUT | POLLWRNORM);
    890  1.31  christos 
    891  1.38   mycroft 	if (events & POLLHUP)
    892  1.38   mycroft 		if (!ISSET(tp->t_state, TS_CARR_ON))
    893  1.38   mycroft 			revents |= POLLHUP;
    894  1.31  christos 
    895  1.38   mycroft 	if (revents == 0) {
    896  1.38   mycroft 		if (events & (POLLIN | POLLHUP | POLLRDNORM))
    897  1.70      fvdl 			selrecord(p, &pti->pt_selr);
    898  1.31  christos 
    899  1.38   mycroft 		if (events & (POLLOUT | POLLWRNORM))
    900  1.70      fvdl 			selrecord(p, &pti->pt_selw);
    901  1.31  christos 	}
    902  1.38   mycroft 
    903  1.38   mycroft 	splx(s);
    904  1.38   mycroft 	return (revents);
    905  1.31  christos }
    906  1.31  christos 
    907  1.65  jdolecek static void
    908  1.65  jdolecek filt_ptcrdetach(struct knote *kn)
    909  1.65  jdolecek {
    910  1.65  jdolecek 	struct pt_softc *pti;
    911  1.65  jdolecek 	int		s;
    912  1.65  jdolecek 
    913  1.65  jdolecek 	pti = kn->kn_hook;
    914  1.65  jdolecek 	s = spltty();
    915  1.66  christos 	SLIST_REMOVE(&pti->pt_selr.sel_klist, kn, knote, kn_selnext);
    916  1.65  jdolecek 	splx(s);
    917  1.65  jdolecek }
    918  1.65  jdolecek 
    919  1.65  jdolecek static int
    920  1.65  jdolecek filt_ptcread(struct knote *kn, long hint)
    921  1.65  jdolecek {
    922  1.65  jdolecek 	struct pt_softc *pti;
    923  1.65  jdolecek 	struct tty	*tp;
    924  1.65  jdolecek 	int canread;
    925  1.65  jdolecek 
    926  1.65  jdolecek 	pti = kn->kn_hook;
    927  1.65  jdolecek 	tp = pti->pt_tty;
    928  1.65  jdolecek 
    929  1.65  jdolecek 	canread = (ISSET(tp->t_state, TS_ISOPEN) &&
    930  1.65  jdolecek 		    ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
    931  1.65  jdolecek 		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
    932  1.65  jdolecek 		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)));
    933  1.65  jdolecek 
    934  1.65  jdolecek 	if (canread) {
    935  1.65  jdolecek 		/*
    936  1.65  jdolecek 		 * c_cc is number of characters after output post-processing;
    937  1.65  jdolecek 		 * the amount of data actually read(2) depends on
    938  1.65  jdolecek 		 * setting of input flags for the terminal.
    939  1.65  jdolecek 		 */
    940  1.65  jdolecek 		kn->kn_data = tp->t_outq.c_cc;
    941  1.65  jdolecek 		if (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
    942  1.65  jdolecek 		    ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))
    943  1.65  jdolecek 			kn->kn_data++;
    944  1.65  jdolecek 	}
    945  1.65  jdolecek 
    946  1.65  jdolecek 	return (canread);
    947  1.65  jdolecek }
    948  1.65  jdolecek 
    949  1.65  jdolecek static void
    950  1.65  jdolecek filt_ptcwdetach(struct knote *kn)
    951  1.65  jdolecek {
    952  1.65  jdolecek 	struct pt_softc *pti;
    953  1.65  jdolecek 	int		s;
    954  1.65  jdolecek 
    955  1.65  jdolecek 	pti = kn->kn_hook;
    956  1.65  jdolecek 	s = spltty();
    957  1.66  christos 	SLIST_REMOVE(&pti->pt_selw.sel_klist, kn, knote, kn_selnext);
    958  1.65  jdolecek 	splx(s);
    959  1.65  jdolecek }
    960  1.65  jdolecek 
    961  1.65  jdolecek static int
    962  1.65  jdolecek filt_ptcwrite(struct knote *kn, long hint)
    963  1.65  jdolecek {
    964  1.65  jdolecek 	struct pt_softc *pti;
    965  1.65  jdolecek 	struct tty	*tp;
    966  1.65  jdolecek 	int canwrite;
    967  1.65  jdolecek 	int nwrite;
    968  1.65  jdolecek 
    969  1.65  jdolecek 	pti = kn->kn_hook;
    970  1.65  jdolecek 	tp = pti->pt_tty;
    971  1.65  jdolecek 
    972  1.65  jdolecek 	canwrite = (ISSET(tp->t_state, TS_ISOPEN) &&
    973  1.65  jdolecek 		    ((pti->pt_flags & PF_REMOTE) ?
    974  1.65  jdolecek 		     (tp->t_canq.c_cc == 0) :
    975  1.65  jdolecek 		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
    976  1.65  jdolecek 		      (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))));
    977  1.65  jdolecek 
    978  1.65  jdolecek 	if (canwrite) {
    979  1.65  jdolecek 		if (pti->pt_flags & PF_REMOTE)
    980  1.65  jdolecek 			nwrite = tp->t_canq.c_cn;
    981  1.65  jdolecek 		else {
    982  1.65  jdolecek 			/* this is guaranteed to be > 0 due to above check */
    983  1.65  jdolecek 			nwrite = tp->t_canq.c_cn
    984  1.65  jdolecek 				- (tp->t_rawq.c_cc + tp->t_canq.c_cc);
    985  1.65  jdolecek 		}
    986  1.65  jdolecek 		kn->kn_data = nwrite;
    987  1.65  jdolecek 	}
    988  1.65  jdolecek 
    989  1.65  jdolecek 	return (canwrite);
    990  1.65  jdolecek }
    991  1.65  jdolecek 
    992  1.65  jdolecek static const struct filterops ptcread_filtops =
    993  1.65  jdolecek 	{ 1, NULL, filt_ptcrdetach, filt_ptcread };
    994  1.65  jdolecek static const struct filterops ptcwrite_filtops =
    995  1.65  jdolecek 	{ 1, NULL, filt_ptcwdetach, filt_ptcwrite };
    996  1.65  jdolecek 
    997  1.65  jdolecek int
    998  1.65  jdolecek ptckqfilter(dev_t dev, struct knote *kn)
    999  1.65  jdolecek {
   1000  1.65  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
   1001  1.65  jdolecek 	struct klist	*klist;
   1002  1.65  jdolecek 	int		s;
   1003  1.65  jdolecek 
   1004  1.65  jdolecek 	switch (kn->kn_filter) {
   1005  1.65  jdolecek 	case EVFILT_READ:
   1006  1.66  christos 		klist = &pti->pt_selr.sel_klist;
   1007  1.65  jdolecek 		kn->kn_fop = &ptcread_filtops;
   1008  1.65  jdolecek 		break;
   1009  1.65  jdolecek 	case EVFILT_WRITE:
   1010  1.66  christos 		klist = &pti->pt_selw.sel_klist;
   1011  1.65  jdolecek 		kn->kn_fop = &ptcwrite_filtops;
   1012  1.65  jdolecek 		break;
   1013  1.65  jdolecek 	default:
   1014  1.65  jdolecek 		return (1);
   1015  1.65  jdolecek 	}
   1016  1.65  jdolecek 
   1017  1.65  jdolecek 	kn->kn_hook = pti;
   1018  1.65  jdolecek 
   1019  1.65  jdolecek 	s = spltty();
   1020  1.65  jdolecek 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
   1021  1.65  jdolecek 	splx(s);
   1022  1.65  jdolecek 
   1023  1.65  jdolecek 	return (0);
   1024  1.65  jdolecek }
   1025  1.31  christos 
   1026  1.29   mycroft struct tty *
   1027  1.29   mycroft ptytty(dev)
   1028  1.29   mycroft 	dev_t dev;
   1029  1.29   mycroft {
   1030  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
   1031  1.43  augustss 	struct tty *tp = pti->pt_tty;
   1032  1.29   mycroft 
   1033  1.29   mycroft 	return (tp);
   1034   1.1       cgd }
   1035   1.1       cgd 
   1036   1.1       cgd /*ARGSUSED*/
   1037  1.31  christos int
   1038  1.70      fvdl ptyioctl(dev, cmd, data, flag, p)
   1039  1.18   mycroft 	dev_t dev;
   1040  1.24       cgd 	u_long cmd;
   1041   1.1       cgd 	caddr_t data;
   1042  1.18   mycroft 	int flag;
   1043  1.70      fvdl 	struct proc *p;
   1044   1.1       cgd {
   1045  1.47  jdolecek 	struct pt_softc *pti = pt_softc[minor(dev)];
   1046  1.43  augustss 	struct tty *tp = pti->pt_tty;
   1047  1.63   gehenna 	const struct cdevsw *cdev;
   1048  1.43  augustss 	u_char *cc = tp->t_cc;
   1049  1.44      fvdl 	int stop, error, sig;
   1050  1.75       dbj 	int s;
   1051   1.1       cgd 
   1052  1.63   gehenna 	cdev = cdevsw_lookup(dev);
   1053   1.1       cgd 	/*
   1054   1.1       cgd 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
   1055   1.1       cgd 	 * ttywflush(tp) will hang if there are characters in the outq.
   1056   1.1       cgd 	 */
   1057   1.1       cgd 	if (cmd == TIOCEXT) {
   1058   1.1       cgd 		/*
   1059   1.1       cgd 		 * When the EXTPROC bit is being toggled, we need
   1060   1.1       cgd 		 * to send an TIOCPKT_IOCTL if the packet driver
   1061   1.1       cgd 		 * is turned on.
   1062   1.1       cgd 		 */
   1063   1.1       cgd 		if (*(int *)data) {
   1064   1.1       cgd 			if (pti->pt_flags & PF_PKT) {
   1065   1.1       cgd 				pti->pt_send |= TIOCPKT_IOCTL;
   1066   1.1       cgd 				ptcwakeup(tp, FREAD);
   1067   1.1       cgd 			}
   1068  1.37   mycroft 			SET(tp->t_lflag, EXTPROC);
   1069   1.1       cgd 		} else {
   1070  1.39      fvdl 			if (ISSET(tp->t_lflag, EXTPROC) &&
   1071   1.1       cgd 			    (pti->pt_flags & PF_PKT)) {
   1072   1.1       cgd 				pti->pt_send |= TIOCPKT_IOCTL;
   1073   1.1       cgd 				ptcwakeup(tp, FREAD);
   1074   1.1       cgd 			}
   1075  1.37   mycroft 			CLR(tp->t_lflag, EXTPROC);
   1076   1.1       cgd 		}
   1077   1.1       cgd 		return(0);
   1078  1.71       dsl 	}
   1079  1.71       dsl 
   1080  1.63   gehenna 	if (cdev != NULL && cdev->d_open == ptcopen)
   1081   1.1       cgd 		switch (cmd) {
   1082  1.77  christos #ifdef NPTM
   1083  1.77  christos 		case TIOCGRANTPT:
   1084  1.77  christos 			return pty_grant_slave(p, dev);
   1085  1.77  christos 
   1086  1.77  christos 		case TIOCPTSNAME:
   1087  1.77  christos 			pty_fill_ptmget(dev, -1, -1, data);
   1088  1.77  christos 			return 0;
   1089  1.77  christos #endif
   1090   1.1       cgd 
   1091   1.1       cgd 		case TIOCGPGRP:
   1092  1.35        pk 			/*
   1093  1.35        pk 			 * We avoid calling ttioctl on the controller since,
   1094   1.1       cgd 			 * in that case, tp must be the controlling terminal.
   1095   1.1       cgd 			 */
   1096   1.1       cgd 			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
   1097   1.1       cgd 			return (0);
   1098   1.1       cgd 
   1099   1.1       cgd 		case TIOCPKT:
   1100   1.1       cgd 			if (*(int *)data) {
   1101   1.1       cgd 				if (pti->pt_flags & PF_UCNTL)
   1102   1.1       cgd 					return (EINVAL);
   1103   1.1       cgd 				pti->pt_flags |= PF_PKT;
   1104   1.1       cgd 			} else
   1105   1.1       cgd 				pti->pt_flags &= ~PF_PKT;
   1106   1.1       cgd 			return (0);
   1107   1.1       cgd 
   1108   1.1       cgd 		case TIOCUCNTL:
   1109   1.1       cgd 			if (*(int *)data) {
   1110   1.1       cgd 				if (pti->pt_flags & PF_PKT)
   1111   1.1       cgd 					return (EINVAL);
   1112   1.1       cgd 				pti->pt_flags |= PF_UCNTL;
   1113   1.1       cgd 			} else
   1114   1.1       cgd 				pti->pt_flags &= ~PF_UCNTL;
   1115   1.1       cgd 			return (0);
   1116   1.1       cgd 
   1117   1.1       cgd 		case TIOCREMOTE:
   1118   1.1       cgd 			if (*(int *)data)
   1119   1.1       cgd 				pti->pt_flags |= PF_REMOTE;
   1120   1.1       cgd 			else
   1121   1.1       cgd 				pti->pt_flags &= ~PF_REMOTE;
   1122  1.75       dbj 			s = spltty();
   1123  1.68        pk 			TTY_LOCK(tp);
   1124   1.1       cgd 			ttyflush(tp, FREAD|FWRITE);
   1125  1.68        pk 			TTY_UNLOCK(tp);
   1126  1.75       dbj 			splx(s);
   1127   1.1       cgd 			return (0);
   1128   1.1       cgd 
   1129  1.32  christos #ifdef COMPAT_OLDTTY
   1130  1.35        pk 		case TIOCSETP:
   1131   1.1       cgd 		case TIOCSETN:
   1132   1.2       cgd #endif
   1133   1.1       cgd 		case TIOCSETD:
   1134   1.1       cgd 		case TIOCSETA:
   1135   1.1       cgd 		case TIOCSETAW:
   1136   1.1       cgd 		case TIOCSETAF:
   1137  1.68        pk 			TTY_LOCK(tp);
   1138  1.21       cgd 			ndflush(&tp->t_outq, tp->t_outq.c_cc);
   1139  1.68        pk 			TTY_UNLOCK(tp);
   1140   1.1       cgd 			break;
   1141   1.1       cgd 
   1142   1.1       cgd 		case TIOCSIG:
   1143  1.46       mrg 			sig = (int)(long)*(caddr_t *)data;
   1144  1.44      fvdl 			if (sig <= 0 || sig >= NSIG)
   1145  1.44      fvdl 				return (EINVAL);
   1146  1.68        pk 			TTY_LOCK(tp);
   1147  1.37   mycroft 			if (!ISSET(tp->t_lflag, NOFLSH))
   1148   1.1       cgd 				ttyflush(tp, FREAD|FWRITE);
   1149  1.44      fvdl 			if ((sig == SIGINFO) &&
   1150  1.37   mycroft 			    (!ISSET(tp->t_lflag, NOKERNINFO)))
   1151   1.1       cgd 				ttyinfo(tp);
   1152  1.68        pk 			TTY_UNLOCK(tp);
   1153  1.62     itohy 			pgsignal(tp->t_pgrp, sig, 1);
   1154   1.1       cgd 			return(0);
   1155   1.1       cgd 		}
   1156  1.71       dsl 
   1157  1.70      fvdl 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
   1158  1.61    atatat 	if (error == EPASSTHROUGH)
   1159  1.70      fvdl 		 error = ttioctl(tp, cmd, data, flag, p);
   1160  1.61    atatat 	if (error == EPASSTHROUGH) {
   1161   1.1       cgd 		if (pti->pt_flags & PF_UCNTL &&
   1162   1.1       cgd 		    (cmd & ~0xff) == UIOCCMD(0)) {
   1163   1.1       cgd 			if (cmd & 0xff) {
   1164   1.1       cgd 				pti->pt_ucntl = (u_char)cmd;
   1165   1.1       cgd 				ptcwakeup(tp, FREAD);
   1166   1.1       cgd 			}
   1167   1.1       cgd 			return (0);
   1168   1.1       cgd 		}
   1169   1.1       cgd 	}
   1170   1.1       cgd 	/*
   1171   1.1       cgd 	 * If external processing and packet mode send ioctl packet.
   1172   1.1       cgd 	 */
   1173  1.37   mycroft 	if (ISSET(tp->t_lflag, EXTPROC) && (pti->pt_flags & PF_PKT)) {
   1174   1.1       cgd 		switch(cmd) {
   1175   1.1       cgd 		case TIOCSETA:
   1176   1.1       cgd 		case TIOCSETAW:
   1177   1.1       cgd 		case TIOCSETAF:
   1178  1.32  christos #ifdef COMPAT_OLDTTY
   1179   1.1       cgd 		case TIOCSETP:
   1180   1.1       cgd 		case TIOCSETN:
   1181   1.1       cgd 		case TIOCSETC:
   1182   1.1       cgd 		case TIOCSLTC:
   1183   1.1       cgd 		case TIOCLBIS:
   1184   1.1       cgd 		case TIOCLBIC:
   1185   1.1       cgd 		case TIOCLSET:
   1186   1.1       cgd #endif
   1187   1.1       cgd 			pti->pt_send |= TIOCPKT_IOCTL;
   1188  1.22       cgd 			ptcwakeup(tp, FREAD);
   1189   1.1       cgd 		default:
   1190   1.1       cgd 			break;
   1191   1.1       cgd 		}
   1192   1.1       cgd 	}
   1193  1.37   mycroft 	stop = ISSET(tp->t_iflag, IXON) && CCEQ(cc[VSTOP], CTRL('s'))
   1194   1.1       cgd 		&& CCEQ(cc[VSTART], CTRL('q'));
   1195   1.1       cgd 	if (pti->pt_flags & PF_NOSTOP) {
   1196   1.1       cgd 		if (stop) {
   1197   1.1       cgd 			pti->pt_send &= ~TIOCPKT_NOSTOP;
   1198   1.1       cgd 			pti->pt_send |= TIOCPKT_DOSTOP;
   1199   1.1       cgd 			pti->pt_flags &= ~PF_NOSTOP;
   1200   1.1       cgd 			ptcwakeup(tp, FREAD);
   1201   1.1       cgd 		}
   1202   1.1       cgd 	} else {
   1203   1.1       cgd 		if (!stop) {
   1204   1.1       cgd 			pti->pt_send &= ~TIOCPKT_DOSTOP;
   1205   1.1       cgd 			pti->pt_send |= TIOCPKT_NOSTOP;
   1206   1.1       cgd 			pti->pt_flags |= PF_NOSTOP;
   1207   1.1       cgd 			ptcwakeup(tp, FREAD);
   1208   1.1       cgd 		}
   1209   1.1       cgd 	}
   1210   1.1       cgd 	return (error);
   1211   1.1       cgd }
   1212  1.77  christos 
   1213  1.77  christos #ifdef NPTM
   1214  1.77  christos /*
   1215  1.77  christos  * Check if a pty is free to use.
   1216  1.77  christos  */
   1217  1.77  christos static __inline int
   1218  1.77  christos pty_isfree_locked(int minor)
   1219  1.77  christos {
   1220  1.77  christos 	struct pt_softc *pt = pt_softc[minor];
   1221  1.77  christos 	return (pt == NULL || pt->pt_tty == NULL ||
   1222  1.77  christos 	    pt->pt_tty->t_oproc == NULL);
   1223  1.77  christos }
   1224  1.77  christos 
   1225  1.77  christos static int
   1226  1.77  christos pty_isfree(int minor)
   1227  1.77  christos {
   1228  1.77  christos 	int isfree;
   1229  1.77  christos 
   1230  1.77  christos 	simple_lock(&pt_softc_mutex);
   1231  1.77  christos 	isfree = pty_isfree_locked(minor);
   1232  1.77  christos 	simple_unlock(&pt_softc_mutex);
   1233  1.77  christos 	return(isfree);
   1234  1.77  christos }
   1235  1.77  christos 
   1236  1.77  christos static char *
   1237  1.77  christos pty_makename(char *buf, dev_t dev, char c)
   1238  1.77  christos {
   1239  1.77  christos 	size_t nt;
   1240  1.77  christos 	dev_t minor = minor(dev);
   1241  1.77  christos 
   1242  1.77  christos 	(void)memcpy(buf, TTY_TEMPLATE, TTY_NAMESIZE);
   1243  1.77  christos 
   1244  1.77  christos 	buf[5] = c;
   1245  1.77  christos 
   1246  1.77  christos 	if (minor < 256) {
   1247  1.77  christos 		nt = sizeof(TTY_OLD_SUFFIX) - 1;
   1248  1.77  christos 		buf[8] = TTY_LETTERS[minor / nt];
   1249  1.77  christos 		buf[9] = TTY_OLD_SUFFIX[minor % nt];
   1250  1.77  christos 	} else {
   1251  1.77  christos 		minor -= 256;
   1252  1.77  christos 		nt = sizeof(TTY_NEW_SUFFIX) - sizeof(TTY_OLD_SUFFIX);
   1253  1.77  christos 		buf[8] = TTY_LETTERS[minor / nt];
   1254  1.77  christos 		buf[9] = TTY_NEW_SUFFIX[minor % nt];
   1255  1.77  christos 	}
   1256  1.77  christos 	return buf;
   1257  1.77  christos }
   1258  1.77  christos 
   1259  1.77  christos static dev_t
   1260  1.77  christos pty_getfree(void)
   1261  1.77  christos {
   1262  1.77  christos 	int i;
   1263  1.77  christos 
   1264  1.77  christos 	simple_lock(&pt_softc_mutex);
   1265  1.77  christos 	for (i = 0; i < npty; i++) {
   1266  1.77  christos 		if (pty_isfree_locked(i))
   1267  1.77  christos 			break;
   1268  1.77  christos 	}
   1269  1.77  christos 	simple_unlock(&pt_softc_mutex);
   1270  1.77  christos 	return (makedev(pts_major, i));
   1271  1.77  christos }
   1272  1.77  christos 
   1273  1.77  christos /*
   1274  1.77  christos  * Hacked up version of vn_open. We _only_ handle ptys and only open
   1275  1.77  christos  * them with FREAD|FWRITE and never deal with creat or stuff like that.
   1276  1.77  christos  *
   1277  1.77  christos  * We need it because we have to fake up root credentials to open the pty.
   1278  1.77  christos  */
   1279  1.77  christos static int
   1280  1.77  christos ptm_vn_open(struct nameidata *ndp)
   1281  1.77  christos {
   1282  1.77  christos 	struct vnode *vp;
   1283  1.77  christos 	struct proc *p = ndp->ni_cnd.cn_proc;
   1284  1.77  christos 	struct ucred *cred;
   1285  1.77  christos 	int error;
   1286  1.77  christos 
   1287  1.77  christos 	if ((error = namei(ndp)) != 0)
   1288  1.77  christos 		return (error);
   1289  1.77  christos 	vp = ndp->ni_vp;
   1290  1.77  christos 	if (vp->v_type != VCHR) {
   1291  1.77  christos 		error = EINVAL;
   1292  1.77  christos 		goto bad;
   1293  1.77  christos 	}
   1294  1.77  christos 
   1295  1.77  christos 	/*
   1296  1.77  christos 	 * Get us a fresh cred with root privileges.
   1297  1.77  christos 	 */
   1298  1.77  christos 	cred = crget();
   1299  1.77  christos 	error = VOP_OPEN(vp, FREAD|FWRITE, cred, p);
   1300  1.77  christos 	crfree(cred);
   1301  1.77  christos 
   1302  1.77  christos 	if (error)
   1303  1.77  christos 		goto bad;
   1304  1.77  christos 
   1305  1.77  christos 	vp->v_writecount++;
   1306  1.77  christos 
   1307  1.77  christos 	return (0);
   1308  1.77  christos bad:
   1309  1.77  christos 	vput(vp);
   1310  1.77  christos 	return (error);
   1311  1.77  christos }
   1312  1.77  christos 
   1313  1.77  christos static int
   1314  1.77  christos pty_alloc_master(struct proc *p, int *fd, dev_t *dev)
   1315  1.77  christos {
   1316  1.77  christos 	int error;
   1317  1.77  christos 	struct nameidata nd;
   1318  1.77  christos 	struct pt_softc *pti;
   1319  1.77  christos 	struct file *fp;
   1320  1.77  christos 	int md;
   1321  1.77  christos 	char name[TTY_NAMESIZE];
   1322  1.77  christos 
   1323  1.77  christos 	if ((error = falloc(p, &fp, fd)) != 0) {
   1324  1.77  christos 		DPRINTF(("falloc %d\n", error));
   1325  1.77  christos 		return error;
   1326  1.77  christos 	}
   1327  1.77  christos retry:
   1328  1.77  christos 	/* Find and open a free master pty. */
   1329  1.77  christos 	*dev = pty_getfree();
   1330  1.77  christos 	md = minor(*dev);
   1331  1.77  christos 	if ((error = check_pty(md)) != 0) {
   1332  1.77  christos 		DPRINTF(("ckeck_pty %d\n", error));
   1333  1.77  christos 		goto bad;
   1334  1.77  christos 	}
   1335  1.77  christos 	pti = pt_softc[md];
   1336  1.77  christos 	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE,
   1337  1.77  christos 	    pty_makename(name, *dev, 'p'), p);
   1338  1.77  christos 	if ((error = ptm_vn_open(&nd)) != 0) {
   1339  1.77  christos 		/*
   1340  1.77  christos 		 * Check if the master open failed because we lost
   1341  1.77  christos 		 * the race to grab it.
   1342  1.77  christos 		 */
   1343  1.77  christos 		if (error == EIO && !pty_isfree(md))
   1344  1.77  christos 			goto retry;
   1345  1.77  christos 		DPRINTF(("check_pty %d\n", error));
   1346  1.77  christos 		goto bad;
   1347  1.77  christos 	}
   1348  1.77  christos 	fp->f_flag = FREAD|FWRITE;
   1349  1.77  christos 	fp->f_type = DTYPE_VNODE;
   1350  1.77  christos 	fp->f_ops = &vnops;
   1351  1.77  christos 	fp->f_data = nd.ni_vp;
   1352  1.77  christos 	VOP_UNLOCK(nd.ni_vp, 0);
   1353  1.77  christos 	FILE_SET_MATURE(fp);
   1354  1.77  christos 	FILE_UNUSE(fp, p);
   1355  1.77  christos 	return 0;
   1356  1.77  christos bad:
   1357  1.77  christos 	FILE_UNUSE(fp, p);
   1358  1.77  christos 	fdremove(p->p_fd, *fd);
   1359  1.77  christos 	ffree(fp);
   1360  1.77  christos 	return error;
   1361  1.77  christos }
   1362  1.77  christos 
   1363  1.77  christos static int
   1364  1.77  christos pty_grant_slave(struct proc *p, dev_t dev)
   1365  1.77  christos {
   1366  1.77  christos 	int error;
   1367  1.77  christos 	struct nameidata nd;
   1368  1.77  christos 	char name[TTY_NAMESIZE];
   1369  1.77  christos 
   1370  1.77  christos 	/*
   1371  1.77  christos 	 * Open the slave.
   1372  1.77  christos 	 * namei -> setattr -> unlock -> revoke -> vrele ->
   1373  1.77  christos 	 * namei -> open -> unlock
   1374  1.77  christos 	 * Three stage rocket:
   1375  1.77  christos 	 * 1. Change the owner and permissions on the slave.
   1376  1.77  christos 	 * 2. Revoke all the users of the slave.
   1377  1.77  christos 	 * 3. open the slave.
   1378  1.77  christos 	 */
   1379  1.77  christos 	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE,
   1380  1.77  christos 	    pty_makename(name, dev, 't'), p);
   1381  1.77  christos 	if ((error = namei(&nd)) != 0) {
   1382  1.77  christos 		DPRINTF(("namei %d\n", error));
   1383  1.77  christos 		return error;
   1384  1.77  christos 	}
   1385  1.77  christos 	if ((nd.ni_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
   1386  1.77  christos 		struct vattr vattr;
   1387  1.77  christos 		struct ucred *cred;
   1388  1.77  christos 		gid_t gid = _TTY_GID;
   1389  1.77  christos 		/* get real uid */
   1390  1.77  christos 		uid_t uid = p->p_cred->p_ruid;
   1391  1.77  christos 
   1392  1.77  christos 		VATTR_NULL(&vattr);
   1393  1.77  christos 		vattr.va_uid = uid;
   1394  1.77  christos 		vattr.va_gid = gid;
   1395  1.77  christos 		vattr.va_mode = (S_IRUSR|S_IWUSR|S_IWGRP) & ALLPERMS;
   1396  1.77  christos 		/* Get a fake cred to pretend we're root. */
   1397  1.77  christos 		cred = crget();
   1398  1.77  christos 		error = VOP_SETATTR(nd.ni_vp, &vattr, cred, p);
   1399  1.77  christos 		crfree(cred);
   1400  1.77  christos 		if (error) {
   1401  1.77  christos 			DPRINTF(("setattr %d\n", error));
   1402  1.77  christos 			VOP_UNLOCK(nd.ni_vp, 0);
   1403  1.77  christos 			vrele(nd.ni_vp);
   1404  1.77  christos 			return error;
   1405  1.77  christos 		}
   1406  1.77  christos 	}
   1407  1.77  christos 	VOP_UNLOCK(nd.ni_vp, 0);
   1408  1.77  christos 	if (nd.ni_vp->v_usecount > 1 ||
   1409  1.77  christos 	    (nd.ni_vp->v_flag & (VALIASED | VLAYER)))
   1410  1.77  christos 		VOP_REVOKE(nd.ni_vp, REVOKEALL);
   1411  1.77  christos 
   1412  1.77  christos 	/*
   1413  1.77  christos 	 * The vnode is useless after the revoke, we need to
   1414  1.77  christos 	 * namei again.
   1415  1.77  christos 	 */
   1416  1.77  christos 	vrele(nd.ni_vp);
   1417  1.77  christos 	return 0;
   1418  1.77  christos }
   1419  1.77  christos 
   1420  1.77  christos static int
   1421  1.77  christos pty_alloc_slave(struct proc *p, int *fd, dev_t dev)
   1422  1.77  christos {
   1423  1.77  christos 	int error;
   1424  1.77  christos 	struct file *fp;
   1425  1.77  christos 	struct nameidata nd;
   1426  1.77  christos 	char name[TTY_NAMESIZE];
   1427  1.77  christos 
   1428  1.77  christos 	/* Grab a filedescriptor for the slave */
   1429  1.77  christos 	if ((error = falloc(p, &fp, fd)) != 0) {
   1430  1.77  christos 		DPRINTF(("falloc %d\n", error));
   1431  1.77  christos 		return error;
   1432  1.77  christos 	}
   1433  1.77  christos 
   1434  1.77  christos 	NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE,
   1435  1.77  christos 	    pty_makename(name, dev, 't'), p);
   1436  1.77  christos 
   1437  1.77  christos 	/* now open it */
   1438  1.77  christos 	if ((error = ptm_vn_open(&nd)) != 0) {
   1439  1.77  christos 		DPRINTF(("vn_open %d\n", error));
   1440  1.77  christos 		FILE_UNUSE(fp, p);
   1441  1.77  christos 		fdremove(p->p_fd, *fd);
   1442  1.77  christos 		ffree(fp);
   1443  1.77  christos 		return error;
   1444  1.77  christos 	}
   1445  1.77  christos 	fp->f_flag = FREAD|FWRITE;
   1446  1.77  christos 	fp->f_type = DTYPE_VNODE;
   1447  1.77  christos 	fp->f_ops = &vnops;
   1448  1.77  christos 	fp->f_data = nd.ni_vp;
   1449  1.77  christos 	VOP_UNLOCK(nd.ni_vp, 0);
   1450  1.77  christos 	FILE_SET_MATURE(fp);
   1451  1.77  christos 	FILE_UNUSE(fp, p);
   1452  1.77  christos 	return 0;
   1453  1.77  christos }
   1454  1.77  christos 
   1455  1.77  christos static void
   1456  1.77  christos pty_fill_ptmget(dev_t dev, int cfd, int sfd, void *data)
   1457  1.77  christos {
   1458  1.77  christos 	struct ptmget *ptm = data;
   1459  1.77  christos 	ptm->cfd = cfd;
   1460  1.77  christos 	ptm->sfd = sfd;
   1461  1.77  christos 	(void)pty_makename(ptm->cn, dev, 'p');
   1462  1.77  christos 	(void)pty_makename(ptm->sn, dev, 't');
   1463  1.77  christos }
   1464  1.77  christos 
   1465  1.77  christos void
   1466  1.77  christos /*ARGSUSED*/
   1467  1.77  christos ptmattach(int n)
   1468  1.77  christos {
   1469  1.77  christos 	/* find the major and minor of the pty devices */
   1470  1.77  christos 	if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
   1471  1.77  christos 		panic("ptmattach: Can't find pty slave in cdevsw");
   1472  1.77  christos }
   1473  1.77  christos 
   1474  1.77  christos int
   1475  1.77  christos /*ARGSUSED*/
   1476  1.77  christos ptmopen(dev_t dev, int flag, int mode, struct proc *p)
   1477  1.77  christos {
   1478  1.77  christos 	int error;
   1479  1.77  christos 	int fd;
   1480  1.77  christos 
   1481  1.77  christos 	switch(minor(dev)) {
   1482  1.77  christos 	case 0:		/* /dev/ptmx */
   1483  1.77  christos 		if ((error = pty_alloc_master(p, &fd, &dev)) != 0)
   1484  1.77  christos 			return error;
   1485  1.77  christos 		curlwp->l_dupfd = fd;
   1486  1.77  christos 		return ENXIO;
   1487  1.77  christos 	case 1:		/* /dev/ptm */
   1488  1.77  christos 		return 0;
   1489  1.77  christos 	default:
   1490  1.77  christos 		return ENODEV;
   1491  1.77  christos 	}
   1492  1.77  christos 
   1493  1.77  christos }
   1494  1.77  christos 
   1495  1.77  christos int
   1496  1.77  christos /*ARGSUSED*/
   1497  1.77  christos ptmclose(dev_t dev, int flag, int mode, struct proc *p)
   1498  1.77  christos {
   1499  1.77  christos 	return (0);
   1500  1.77  christos }
   1501  1.77  christos 
   1502  1.77  christos int
   1503  1.77  christos /*ARGSUSED*/
   1504  1.77  christos ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
   1505  1.77  christos {
   1506  1.77  christos 	int error;
   1507  1.77  christos 	dev_t newdev;
   1508  1.77  christos 	int cfd, sfd;
   1509  1.77  christos 	struct file *fp;
   1510  1.77  christos 
   1511  1.77  christos 	error = 0;
   1512  1.77  christos 	switch (cmd) {
   1513  1.77  christos 	case TIOCPTMGET:
   1514  1.77  christos 		if ((error = pty_alloc_master(p, &cfd, &newdev)) != 0)
   1515  1.77  christos 			goto bad;
   1516  1.77  christos 
   1517  1.77  christos 		if ((error = pty_grant_slave(p, newdev)) != 0)
   1518  1.77  christos 			goto bad;
   1519  1.77  christos 
   1520  1.77  christos 		if ((error = pty_alloc_slave(p, &sfd, newdev)) != 0)
   1521  1.77  christos 			goto bad;
   1522  1.77  christos 
   1523  1.77  christos 		/* now, put the indices and names into struct ptmget */
   1524  1.77  christos 		pty_fill_ptmget(newdev, cfd, sfd, data);
   1525  1.77  christos 		return 0;
   1526  1.77  christos 	default:
   1527  1.77  christos 		DPRINTF(("ptmioctl EINVAL\n"));
   1528  1.77  christos 		return EINVAL;
   1529  1.77  christos 	}
   1530  1.77  christos bad:
   1531  1.77  christos 	fp = fd_getfile(p->p_fd, cfd);
   1532  1.77  christos 	fdremove(p->p_fd, cfd);
   1533  1.77  christos 	ffree(fp);
   1534  1.77  christos 	return error;
   1535  1.77  christos }
   1536  1.77  christos #endif
   1537