xref: /titanic_44/usr/src/uts/common/io/tty_pty.c (revision 193974072f41a843678abf5f61979c748687e66b)
17c478bd9Sstevel@tonic-gate /*
2*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
87c478bd9Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
97c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
107c478bd9Sstevel@tonic-gate  */
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate /*
137c478bd9Sstevel@tonic-gate  * PTY - Stream "pseudo-tty" device.  For each "controller" side
147c478bd9Sstevel@tonic-gate  * it connects to a "slave" side.
157c478bd9Sstevel@tonic-gate  */
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate #include <sys/param.h>
197c478bd9Sstevel@tonic-gate #include <sys/systm.h>
207c478bd9Sstevel@tonic-gate #include <sys/filio.h>
217c478bd9Sstevel@tonic-gate #include <sys/ioccom.h>
227c478bd9Sstevel@tonic-gate #include <sys/termios.h>
237c478bd9Sstevel@tonic-gate #include <sys/termio.h>
247c478bd9Sstevel@tonic-gate #include <sys/ttold.h>
257c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
267c478bd9Sstevel@tonic-gate #include <sys/stream.h>
277c478bd9Sstevel@tonic-gate #include <sys/tty.h>
287c478bd9Sstevel@tonic-gate #include <sys/user.h>
297c478bd9Sstevel@tonic-gate #include <sys/conf.h>
307c478bd9Sstevel@tonic-gate #include <sys/file.h>
317c478bd9Sstevel@tonic-gate #include <sys/vnode.h>	/* 1/0 on the vomit meter */
327c478bd9Sstevel@tonic-gate #include <sys/proc.h>
337c478bd9Sstevel@tonic-gate #include <sys/uio.h>
347c478bd9Sstevel@tonic-gate #include <sys/errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
367c478bd9Sstevel@tonic-gate #include <sys/poll.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/debug.h>
397c478bd9Sstevel@tonic-gate #include <sys/procset.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h>
427c478bd9Sstevel@tonic-gate #include <sys/suntty.h>
437c478bd9Sstevel@tonic-gate #include <sys/stat.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <sys/conf.h>
467c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate extern int npty;	/* number of pseudo-ttys configured in */
507c478bd9Sstevel@tonic-gate extern struct pty *pty_softc;
517c478bd9Sstevel@tonic-gate extern struct pollhead	ptcph;	/* poll head for ptcpoll() use */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate int ptcopen(dev_t *, int, int, struct cred *);
547c478bd9Sstevel@tonic-gate int ptcclose(dev_t, int, int, struct cred *);
557c478bd9Sstevel@tonic-gate int ptcwrite(dev_t, struct uio *, struct cred *);
567c478bd9Sstevel@tonic-gate int ptcread(dev_t, struct uio *, struct cred *);
577c478bd9Sstevel@tonic-gate int ptcioctl(dev_t, int, intptr_t, int, struct cred *, int *);
587c478bd9Sstevel@tonic-gate int ptcpoll(dev_t, short, int, short *, struct pollhead **);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static int ptc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
617c478bd9Sstevel@tonic-gate static int ptc_attach(dev_info_t *, ddi_attach_cmd_t);
627c478bd9Sstevel@tonic-gate static dev_info_t *ptc_dip;	/* for dev-to-dip conversions */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static void ptc_init(void), ptc_uninit(void);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static int makemsg(ssize_t count, struct uio *uiop,
677c478bd9Sstevel@tonic-gate     struct pty *pty, mblk_t **mpp);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate struct cb_ops	ptc_cb_ops = {
707c478bd9Sstevel@tonic-gate 	ptcopen,		/* open */
717c478bd9Sstevel@tonic-gate 	ptcclose,		/* close */
727c478bd9Sstevel@tonic-gate 	nodev,			/* strategy */
737c478bd9Sstevel@tonic-gate 	nodev,			/* print */
747c478bd9Sstevel@tonic-gate 	nodev,			/* dump */
757c478bd9Sstevel@tonic-gate 	ptcread,		/* read */
767c478bd9Sstevel@tonic-gate 	ptcwrite,		/* write */
777c478bd9Sstevel@tonic-gate 	ptcioctl, 		/* ioctl */
787c478bd9Sstevel@tonic-gate 	nodev,			/* devmap */
797c478bd9Sstevel@tonic-gate 	nodev,			/* mmap */
807c478bd9Sstevel@tonic-gate 	nodev,			/* segmap */
817c478bd9Sstevel@tonic-gate 	ptcpoll,		/* poll */
827c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* prop_op */
837c478bd9Sstevel@tonic-gate 	0,			/* streamtab */
847c478bd9Sstevel@tonic-gate 	D_NEW | D_MP		/* Driver compatibility flag */
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate struct dev_ops	ptc_ops = {
887c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
897c478bd9Sstevel@tonic-gate 	0,			/* refcnt */
907c478bd9Sstevel@tonic-gate 	ptc_info,		/* info */
917c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
927c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
937c478bd9Sstevel@tonic-gate 	ptc_attach,		/* attach */
947c478bd9Sstevel@tonic-gate 	nodev,			/* detach */
957c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
967c478bd9Sstevel@tonic-gate 	&ptc_cb_ops,		/* driver operations */
97*19397407SSherry Moore 	(struct bus_ops *)0,	/* bus operations */
98*19397407SSherry Moore 	NULL,			/* power */
99*19397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #include <sys/types.h>
1037c478bd9Sstevel@tonic-gate #include <sys/conf.h>
1047c478bd9Sstevel@tonic-gate #include <sys/param.h>
1057c478bd9Sstevel@tonic-gate #include <sys/systm.h>
1067c478bd9Sstevel@tonic-gate #include <sys/errno.h>
1077c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate extern int dseekneg_flag;
1107c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
1117c478bd9Sstevel@tonic-gate extern struct dev_ops ptc_ops;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1157c478bd9Sstevel@tonic-gate  */
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1187c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
119*19397407SSherry Moore 	"tty pseudo driver control 'ptc'",
1207c478bd9Sstevel@tonic-gate 	&ptc_ops,	/* driver ops */
1217c478bd9Sstevel@tonic-gate };
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1247c478bd9Sstevel@tonic-gate 	MODREV_1,
1257c478bd9Sstevel@tonic-gate 	&modldrv,
1267c478bd9Sstevel@tonic-gate 	NULL
1277c478bd9Sstevel@tonic-gate };
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate int
_init()1307c478bd9Sstevel@tonic-gate _init()
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	int rc;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if ((rc = mod_install(&modlinkage)) == 0)
1357c478bd9Sstevel@tonic-gate 		ptc_init();
1367c478bd9Sstevel@tonic-gate 	return (rc);
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate int
_fini()1417c478bd9Sstevel@tonic-gate _fini()
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	int rc;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if ((rc = mod_remove(&modlinkage)) == 0)
1467c478bd9Sstevel@tonic-gate 		ptc_uninit();
1477c478bd9Sstevel@tonic-gate 	return (rc);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1517c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static char	*pty_banks = PTY_BANKS;
1577c478bd9Sstevel@tonic-gate static char	*pty_digits = PTY_DIGITS;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /* ARGSUSED */
1607c478bd9Sstevel@tonic-gate static int
ptc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)1617c478bd9Sstevel@tonic-gate ptc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate 	char	name[8];
1647c478bd9Sstevel@tonic-gate 	int	pty_num;
1657c478bd9Sstevel@tonic-gate 	char	*pty_digit = pty_digits;
1667c478bd9Sstevel@tonic-gate 	char	*pty_bank = pty_banks;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	for (pty_num = 0; pty_num < npty; pty_num++) {
1697c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "pty%c%c", *pty_bank, *pty_digit);
1707c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(devi, name, S_IFCHR,
1717c478bd9Sstevel@tonic-gate 		    pty_num, DDI_PSEUDO, NULL) == DDI_FAILURE) {
1727c478bd9Sstevel@tonic-gate 			ddi_remove_minor_node(devi, NULL);
1737c478bd9Sstevel@tonic-gate 			return (-1);
1747c478bd9Sstevel@tonic-gate 		}
1757c478bd9Sstevel@tonic-gate 		if (*(++pty_digit) == '\0') {
1767c478bd9Sstevel@tonic-gate 			pty_digit = pty_digits;
1777c478bd9Sstevel@tonic-gate 			if (*(++pty_bank) == '\0')
1787c478bd9Sstevel@tonic-gate 				break;
1797c478bd9Sstevel@tonic-gate 		}
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 	ptc_dip = devi;
1827c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /* ARGSUSED */
1867c478bd9Sstevel@tonic-gate static int
ptc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)1877c478bd9Sstevel@tonic-gate ptc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	int error;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	switch (infocmd) {
1927c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
1937c478bd9Sstevel@tonic-gate 		if (ptc_dip == NULL) {
1947c478bd9Sstevel@tonic-gate 			*result = (void *)NULL;
1957c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
1967c478bd9Sstevel@tonic-gate 		} else {
1977c478bd9Sstevel@tonic-gate 			*result = (void *) ptc_dip;
1987c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 		break;
2017c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2027c478bd9Sstevel@tonic-gate 		*result = (void *)0;
2037c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
2047c478bd9Sstevel@tonic-gate 		break;
2057c478bd9Sstevel@tonic-gate 	default:
2067c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 	return (error);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate static void
ptc_init(void)2127c478bd9Sstevel@tonic-gate ptc_init(void)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	minor_t dev;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	for (dev = 0; dev < npty; dev++) {
2177c478bd9Sstevel@tonic-gate 		cv_init(&pty_softc[dev].pt_cv_flags, NULL, CV_DEFAULT, NULL);
2187c478bd9Sstevel@tonic-gate 		cv_init(&pty_softc[dev].pt_cv_readq, NULL, CV_DEFAULT, NULL);
2197c478bd9Sstevel@tonic-gate 		cv_init(&pty_softc[dev].pt_cv_writeq, NULL, CV_DEFAULT, NULL);
2207c478bd9Sstevel@tonic-gate 		mutex_init(&pty_softc[dev].ptc_lock, NULL, MUTEX_DEFAULT, NULL);
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static void
ptc_uninit(void)2257c478bd9Sstevel@tonic-gate ptc_uninit(void)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	minor_t dev;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	for (dev = 0; dev < npty; dev++) {
2307c478bd9Sstevel@tonic-gate 		cv_destroy(&pty_softc[dev].pt_cv_flags);
2317c478bd9Sstevel@tonic-gate 		cv_destroy(&pty_softc[dev].pt_cv_readq);
2327c478bd9Sstevel@tonic-gate 		cv_destroy(&pty_softc[dev].pt_cv_writeq);
2337c478bd9Sstevel@tonic-gate 		mutex_destroy(&pty_softc[dev].ptc_lock);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * Controller side.  This is not, alas, a streams device; there are too
2397c478bd9Sstevel@tonic-gate  * many old features that we must support and that don't work well
2407c478bd9Sstevel@tonic-gate  * with streams.
2417c478bd9Sstevel@tonic-gate  */
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2447c478bd9Sstevel@tonic-gate int
ptcopen(dev_t * devp,int flag,int otyp,struct cred * cred)2457c478bd9Sstevel@tonic-gate ptcopen(dev_t *devp, int flag, int otyp, struct cred *cred)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	dev_t dev = *devp;
2487c478bd9Sstevel@tonic-gate 	struct pty *pty;
2497c478bd9Sstevel@tonic-gate 	queue_t *q;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	if (getminor(dev) >= npty) {
2527c478bd9Sstevel@tonic-gate 		return (ENXIO);
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 	pty = &pty_softc[getminor(dev)];
2557c478bd9Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
2567c478bd9Sstevel@tonic-gate 	if (pty->pt_flags & PF_CARR_ON) {
2577c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
2587c478bd9Sstevel@tonic-gate 		return (EIO);	/* controller is exclusive use */
2597c478bd9Sstevel@tonic-gate 				/* XXX - should be EBUSY! */
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 	if (pty->pt_flags & PF_WOPEN) {
2627c478bd9Sstevel@tonic-gate 		pty->pt_flags &= ~PF_WOPEN;
2637c478bd9Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_flags);
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if ((q = pty->pt_ttycommon.t_readq) != NULL) {
2677c478bd9Sstevel@tonic-gate 		/*
2687c478bd9Sstevel@tonic-gate 		 * Send an un-hangup to the slave, since "carrier" is
2697c478bd9Sstevel@tonic-gate 		 * coming back up.  Make sure we're doing canonicalization.
2707c478bd9Sstevel@tonic-gate 		 */
2717c478bd9Sstevel@tonic-gate 		(void) putctl(q, M_UNHANGUP);
2727c478bd9Sstevel@tonic-gate 		(void) putctl1(q, M_CTL, MC_DOCANON);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	pty->pt_flags |= PF_CARR_ON;
2757c478bd9Sstevel@tonic-gate 	pty->pt_send = 0;
2767c478bd9Sstevel@tonic-gate 	pty->pt_ucntl = 0;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
2797c478bd9Sstevel@tonic-gate 	return (0);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
2837c478bd9Sstevel@tonic-gate int
ptcclose(dev_t dev,int flag,int otyp,struct cred * cred)2847c478bd9Sstevel@tonic-gate ptcclose(dev_t dev, int flag, int otyp, struct cred *cred)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	struct pty *pty;
2877c478bd9Sstevel@tonic-gate 	mblk_t *bp;
2887c478bd9Sstevel@tonic-gate 	queue_t *q;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	pty = &pty_softc[getminor(dev)];
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
2937c478bd9Sstevel@tonic-gate 	if ((q = pty->pt_ttycommon.t_readq) != NULL) {
2947c478bd9Sstevel@tonic-gate 		/*
2957c478bd9Sstevel@tonic-gate 		 * Send a hangup to the slave, since "carrier" is dropping.
2967c478bd9Sstevel@tonic-gate 		 */
2977c478bd9Sstevel@tonic-gate 		(void) putctl(q, M_HANGUP);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	/*
3017c478bd9Sstevel@tonic-gate 	 * Clear out all the controller-side state.  This also
3027c478bd9Sstevel@tonic-gate 	 * clears PF_CARR_ON, which is correct because the
3037c478bd9Sstevel@tonic-gate 	 * "carrier" is dropping since the controller process
3047c478bd9Sstevel@tonic-gate 	 * is going away.
3057c478bd9Sstevel@tonic-gate 	 */
3067c478bd9Sstevel@tonic-gate 	pty->pt_flags &= (PF_WOPEN|PF_STOPPED|PF_NOSTOP);
3077c478bd9Sstevel@tonic-gate 	while ((bp = pty->pt_stuffqfirst) != NULL) {
3087c478bd9Sstevel@tonic-gate 		if ((pty->pt_stuffqfirst = bp->b_next) == NULL)
3097c478bd9Sstevel@tonic-gate 			pty->pt_stuffqlast = NULL;
3107c478bd9Sstevel@tonic-gate 		else
3117c478bd9Sstevel@tonic-gate 			pty->pt_stuffqfirst->b_prev = NULL;
3127c478bd9Sstevel@tonic-gate 		pty->pt_stuffqlen--;
3137c478bd9Sstevel@tonic-gate 		bp->b_next = bp->b_prev = NULL;
3147c478bd9Sstevel@tonic-gate 		freemsg(bp);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
3177c478bd9Sstevel@tonic-gate 	return (0);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate int
ptcread(dev_t dev,struct uio * uio,struct cred * cred)3217c478bd9Sstevel@tonic-gate ptcread(dev_t dev, struct uio *uio, struct cred *cred)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	struct pty *pty = &pty_softc[getminor(dev)];
3247c478bd9Sstevel@tonic-gate 	mblk_t *bp, *nbp;
3257c478bd9Sstevel@tonic-gate 	queue_t *q;
3267c478bd9Sstevel@tonic-gate 	unsigned char tmp;
3277c478bd9Sstevel@tonic-gate 	ssize_t cc;
3287c478bd9Sstevel@tonic-gate 	int error;
3297c478bd9Sstevel@tonic-gate 	off_t off;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate #ifdef lint
3327c478bd9Sstevel@tonic-gate 	cred = cred;
3337c478bd9Sstevel@tonic-gate #endif
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	off = uio->uio_offset;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	for (;;) {
3407c478bd9Sstevel@tonic-gate 		while (pty->pt_flags & PF_READ) {
3417c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_WREAD;
3427c478bd9Sstevel@tonic-gate 			cv_wait(&pty->pt_cv_flags, &pty->ptc_lock);
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 		pty->pt_flags |= PF_READ;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 		/*
3477c478bd9Sstevel@tonic-gate 		 * If there's a TIOCPKT packet waiting, pass it back.
3487c478bd9Sstevel@tonic-gate 		 */
3497c478bd9Sstevel@tonic-gate 		while (pty->pt_flags&(PF_PKT|PF_UCNTL) && pty->pt_send) {
3507c478bd9Sstevel@tonic-gate 			tmp = pty->pt_send;
3517c478bd9Sstevel@tonic-gate 			pty->pt_send = 0;
3527c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
3537c478bd9Sstevel@tonic-gate 			error = ureadc((int)tmp, uio);
3547c478bd9Sstevel@tonic-gate 			uio->uio_offset = off;
3557c478bd9Sstevel@tonic-gate 			mutex_enter(&pty->ptc_lock);
3567c478bd9Sstevel@tonic-gate 			if (error) {
3577c478bd9Sstevel@tonic-gate 				pty->pt_send |= tmp;
3587c478bd9Sstevel@tonic-gate 				goto out;
3597c478bd9Sstevel@tonic-gate 			}
3607c478bd9Sstevel@tonic-gate 			if (pty->pt_send == 0)
3617c478bd9Sstevel@tonic-gate 				goto out;
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		/*
3657c478bd9Sstevel@tonic-gate 		 * If there's a user-control packet waiting, pass the
3667c478bd9Sstevel@tonic-gate 		 * "ioctl" code back.
3677c478bd9Sstevel@tonic-gate 		 */
3687c478bd9Sstevel@tonic-gate 		while ((pty->pt_flags & (PF_UCNTL|PF_43UCNTL)) &&
3697c478bd9Sstevel@tonic-gate 		    pty->pt_ucntl) {
3707c478bd9Sstevel@tonic-gate 			tmp = pty->pt_ucntl;
3717c478bd9Sstevel@tonic-gate 			pty->pt_ucntl = 0;
3727c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
3737c478bd9Sstevel@tonic-gate 			error = ureadc((int)tmp, uio);
3747c478bd9Sstevel@tonic-gate 			uio->uio_offset = off;
3757c478bd9Sstevel@tonic-gate 			mutex_enter(&pty->ptc_lock);
3767c478bd9Sstevel@tonic-gate 			if (error) {
3777c478bd9Sstevel@tonic-gate 				if (pty->pt_ucntl == 0)
3787c478bd9Sstevel@tonic-gate 					pty->pt_ucntl = tmp;
3797c478bd9Sstevel@tonic-gate 				goto out;
3807c478bd9Sstevel@tonic-gate 			}
3817c478bd9Sstevel@tonic-gate 			if (pty->pt_ucntl == 0)
3827c478bd9Sstevel@tonic-gate 				goto out;
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		/*
3867c478bd9Sstevel@tonic-gate 		 * If there's any data waiting, pass it back.
3877c478bd9Sstevel@tonic-gate 		 */
3887c478bd9Sstevel@tonic-gate 		if ((q = pty->pt_ttycommon.t_writeq) != NULL &&
3897c478bd9Sstevel@tonic-gate 		    q->q_first != NULL &&
3907c478bd9Sstevel@tonic-gate 		    !(pty->pt_flags & PF_STOPPED)) {
3917c478bd9Sstevel@tonic-gate 			if (pty->pt_flags & (PF_PKT|PF_UCNTL|PF_43UCNTL)) {
3927c478bd9Sstevel@tonic-gate 				/*
3937c478bd9Sstevel@tonic-gate 				 * We're about to begin a move in packet or
3947c478bd9Sstevel@tonic-gate 				 * user-control mode; precede the data with a
3957c478bd9Sstevel@tonic-gate 				 * data header.
3967c478bd9Sstevel@tonic-gate 				 */
3977c478bd9Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
3987c478bd9Sstevel@tonic-gate 				error = ureadc(TIOCPKT_DATA, uio);
3997c478bd9Sstevel@tonic-gate 				uio->uio_offset = off;
4007c478bd9Sstevel@tonic-gate 				mutex_enter(&pty->ptc_lock);
4017c478bd9Sstevel@tonic-gate 				if (error != 0)
4027c478bd9Sstevel@tonic-gate 					goto out;
4037c478bd9Sstevel@tonic-gate 				if ((q = pty->pt_ttycommon.t_writeq) == NULL)
4047c478bd9Sstevel@tonic-gate 					goto out;
4057c478bd9Sstevel@tonic-gate 			}
4067c478bd9Sstevel@tonic-gate 			if ((bp = getq(q)) == NULL)
4077c478bd9Sstevel@tonic-gate 				goto out;
4087c478bd9Sstevel@tonic-gate 			while (uio->uio_resid > 0) {
4097c478bd9Sstevel@tonic-gate 				while ((cc = bp->b_wptr - bp->b_rptr) == 0) {
4107c478bd9Sstevel@tonic-gate 					nbp = bp->b_cont;
4117c478bd9Sstevel@tonic-gate 					freeb(bp);
4127c478bd9Sstevel@tonic-gate 					if ((bp = nbp) == NULL) {
4137c478bd9Sstevel@tonic-gate 						if ((q == NULL) ||
4147c478bd9Sstevel@tonic-gate 						    (bp = getq(q)) == NULL)
4157c478bd9Sstevel@tonic-gate 							goto out;
4167c478bd9Sstevel@tonic-gate 					}
4177c478bd9Sstevel@tonic-gate 				}
4187c478bd9Sstevel@tonic-gate 				cc = MIN(cc, uio->uio_resid);
4197c478bd9Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
4207c478bd9Sstevel@tonic-gate 				error = uiomove((caddr_t)bp->b_rptr,
4217c478bd9Sstevel@tonic-gate 				    cc, UIO_READ, uio);
4227c478bd9Sstevel@tonic-gate 				uio->uio_offset = off;
4237c478bd9Sstevel@tonic-gate 				mutex_enter(&pty->ptc_lock);
4247c478bd9Sstevel@tonic-gate 				if (error != 0) {
4257c478bd9Sstevel@tonic-gate 					freemsg(bp);
4267c478bd9Sstevel@tonic-gate 					goto out;
4277c478bd9Sstevel@tonic-gate 				}
4287c478bd9Sstevel@tonic-gate 				q = pty->pt_ttycommon.t_writeq;
4297c478bd9Sstevel@tonic-gate 				bp->b_rptr += cc;
4307c478bd9Sstevel@tonic-gate 			}
4317c478bd9Sstevel@tonic-gate 			/*
4327c478bd9Sstevel@tonic-gate 			 * Strip off zero-length blocks from the front of
4337c478bd9Sstevel@tonic-gate 			 * what we're putting back on the queue.
4347c478bd9Sstevel@tonic-gate 			 */
4357c478bd9Sstevel@tonic-gate 			while ((bp->b_wptr - bp->b_rptr) == 0) {
4367c478bd9Sstevel@tonic-gate 				nbp = bp->b_cont;
4377c478bd9Sstevel@tonic-gate 				freeb(bp);
4387c478bd9Sstevel@tonic-gate 				if ((bp = nbp) == NULL)
4397c478bd9Sstevel@tonic-gate 					goto out;	/* nothing left */
4407c478bd9Sstevel@tonic-gate 			}
4417c478bd9Sstevel@tonic-gate 			if (q != NULL)
4427c478bd9Sstevel@tonic-gate 				(void) putbq(q, bp);
4437c478bd9Sstevel@tonic-gate 			else
4447c478bd9Sstevel@tonic-gate 				freemsg(bp);
4457c478bd9Sstevel@tonic-gate 			goto out;
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		/*
4497c478bd9Sstevel@tonic-gate 		 * If there's any TIOCSTI-stuffed characters, pass
4507c478bd9Sstevel@tonic-gate 		 * them back.  (They currently arrive after all output;
4517c478bd9Sstevel@tonic-gate 		 * is this correct?)
4527c478bd9Sstevel@tonic-gate 		 */
4537c478bd9Sstevel@tonic-gate 		if (pty->pt_flags&PF_UCNTL && pty->pt_stuffqfirst != NULL) {
4547c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
4557c478bd9Sstevel@tonic-gate 			error = ureadc(TIOCSTI&0xff, uio);
4567c478bd9Sstevel@tonic-gate 			mutex_enter(&pty->ptc_lock);
4577c478bd9Sstevel@tonic-gate 			while (error == 0 &&
4587c478bd9Sstevel@tonic-gate 			    (bp = pty->pt_stuffqfirst) != NULL &&
4597c478bd9Sstevel@tonic-gate 			    uio->uio_resid > 0) {
4607c478bd9Sstevel@tonic-gate 				pty->pt_stuffqlen--;
4617c478bd9Sstevel@tonic-gate 				if ((pty->pt_stuffqfirst = bp->b_next) == NULL)
4627c478bd9Sstevel@tonic-gate 					pty->pt_stuffqlast = NULL;
4637c478bd9Sstevel@tonic-gate 				else
4647c478bd9Sstevel@tonic-gate 					pty->pt_stuffqfirst->b_prev = NULL;
4657c478bd9Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
4667c478bd9Sstevel@tonic-gate 				error = ureadc((int)*bp->b_rptr, uio);
4677c478bd9Sstevel@tonic-gate 				bp->b_next = bp->b_prev = NULL;
4687c478bd9Sstevel@tonic-gate 				freemsg(bp);
4697c478bd9Sstevel@tonic-gate 				mutex_enter(&pty->ptc_lock);
4707c478bd9Sstevel@tonic-gate 			}
4717c478bd9Sstevel@tonic-gate 			uio->uio_offset = off;
4727c478bd9Sstevel@tonic-gate 			goto out;
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		/*
4767c478bd9Sstevel@tonic-gate 		 * There's no data available.
4777c478bd9Sstevel@tonic-gate 		 * We want to block until the slave is open, and there's
4787c478bd9Sstevel@tonic-gate 		 * something to read; but if we lost the slave or we're NBIO,
4797c478bd9Sstevel@tonic-gate 		 * then return the appropriate error instead.  POSIX-style
4807c478bd9Sstevel@tonic-gate 		 * non-block has top billing and gives -1 with errno = EAGAIN,
4817c478bd9Sstevel@tonic-gate 		 * BSD-style comes next and gives -1 with errno = EWOULDBLOCK,
4827c478bd9Sstevel@tonic-gate 		 * SVID-style comes last and gives 0.
4837c478bd9Sstevel@tonic-gate 		 */
4847c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_SLAVEGONE) {
4857c478bd9Sstevel@tonic-gate 			error = EIO;
4867c478bd9Sstevel@tonic-gate 			goto out;
4877c478bd9Sstevel@tonic-gate 		}
4887c478bd9Sstevel@tonic-gate 		if (uio->uio_fmode & FNONBLOCK) {
4897c478bd9Sstevel@tonic-gate 			error = EAGAIN;
4907c478bd9Sstevel@tonic-gate 			goto out;
4917c478bd9Sstevel@tonic-gate 		}
4927c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_NBIO) {
4937c478bd9Sstevel@tonic-gate 			error = EWOULDBLOCK;
4947c478bd9Sstevel@tonic-gate 			goto out;
4957c478bd9Sstevel@tonic-gate 		}
4967c478bd9Sstevel@tonic-gate 		if (uio->uio_fmode & FNDELAY)
4977c478bd9Sstevel@tonic-gate 			goto out;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_WREAD)
5007c478bd9Sstevel@tonic-gate 			cv_broadcast(&pty->pt_cv_flags);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		pty->pt_flags &= ~(PF_READ | PF_WREAD);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&pty->pt_cv_writeq, &pty->ptc_lock)) {
5067c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
5077c478bd9Sstevel@tonic-gate 			return (EINTR);
5087c478bd9Sstevel@tonic-gate 		}
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate out:
5127c478bd9Sstevel@tonic-gate 	if (pty->pt_flags & PF_WREAD)
5137c478bd9Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_flags);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	pty->pt_flags &= ~(PF_READ | PF_WREAD);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
5187c478bd9Sstevel@tonic-gate 	return (error);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate int
ptcwrite(dev_t dev,struct uio * uio,struct cred * cred)5227c478bd9Sstevel@tonic-gate ptcwrite(dev_t dev, struct uio *uio, struct cred *cred)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	struct pty *pty = &pty_softc[getminor(dev)];
5257c478bd9Sstevel@tonic-gate 	queue_t *q;
5267c478bd9Sstevel@tonic-gate 	int written;
5277c478bd9Sstevel@tonic-gate 	mblk_t *mp;
5287c478bd9Sstevel@tonic-gate 	int fmode = 0;
5297c478bd9Sstevel@tonic-gate 	int error = 0;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	off_t off;
5327c478bd9Sstevel@tonic-gate 	off = uio->uio_offset;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate #ifdef lint
5357c478bd9Sstevel@tonic-gate 	cred = cred;
5367c478bd9Sstevel@tonic-gate #endif
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate again:
5427c478bd9Sstevel@tonic-gate 	while (pty->pt_flags & PF_WRITE) {
5437c478bd9Sstevel@tonic-gate 		pty->pt_flags |= PF_WWRITE;
5447c478bd9Sstevel@tonic-gate 		cv_wait(&pty->pt_cv_flags, &pty->ptc_lock);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	pty->pt_flags |= PF_WRITE;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if ((q = pty->pt_ttycommon.t_readq) == NULL) {
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		/*
5527c478bd9Sstevel@tonic-gate 		 * Wait for slave to open.
5537c478bd9Sstevel@tonic-gate 		 */
5547c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_SLAVEGONE) {
5557c478bd9Sstevel@tonic-gate 			error = EIO;
5567c478bd9Sstevel@tonic-gate 			goto out;
5577c478bd9Sstevel@tonic-gate 		}
5587c478bd9Sstevel@tonic-gate 		if (uio->uio_fmode & FNONBLOCK) {
5597c478bd9Sstevel@tonic-gate 			error = EAGAIN;
5607c478bd9Sstevel@tonic-gate 			goto out;
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_NBIO) {
5637c478bd9Sstevel@tonic-gate 			error = EWOULDBLOCK;
5647c478bd9Sstevel@tonic-gate 			goto out;
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 		if (uio->uio_fmode & FNDELAY)
5677c478bd9Sstevel@tonic-gate 			goto out;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_WWRITE)
5707c478bd9Sstevel@tonic-gate 			cv_broadcast(&pty->pt_cv_flags);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		pty->pt_flags &= ~(PF_WRITE | PF_WWRITE);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&pty->pt_cv_readq, &pty->ptc_lock)) {
5757c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
5767c478bd9Sstevel@tonic-gate 			return (EINTR);
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 		goto again;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	/*
5837c478bd9Sstevel@tonic-gate 	 * If in remote mode, even zero-length writes generate messages.
5847c478bd9Sstevel@tonic-gate 	 */
5857c478bd9Sstevel@tonic-gate 	written = 0;
5867c478bd9Sstevel@tonic-gate 	if ((pty->pt_flags & PF_REMOTE) || uio->uio_resid > 0) {
5877c478bd9Sstevel@tonic-gate 		do {
5887c478bd9Sstevel@tonic-gate 			while (!canput(q)) {
5897c478bd9Sstevel@tonic-gate 				/*
5907c478bd9Sstevel@tonic-gate 				 * Wait for slave's read queue to unclog.
5917c478bd9Sstevel@tonic-gate 				 */
5927c478bd9Sstevel@tonic-gate 				if (pty->pt_flags & PF_SLAVEGONE) {
5937c478bd9Sstevel@tonic-gate 					error = EIO;
5947c478bd9Sstevel@tonic-gate 					goto out;
5957c478bd9Sstevel@tonic-gate 				}
5967c478bd9Sstevel@tonic-gate 				if (uio->uio_fmode & FNONBLOCK) {
5977c478bd9Sstevel@tonic-gate 					if (!written)
5987c478bd9Sstevel@tonic-gate 						error = EAGAIN;
5997c478bd9Sstevel@tonic-gate 					goto out;
6007c478bd9Sstevel@tonic-gate 				}
6017c478bd9Sstevel@tonic-gate 				if (pty->pt_flags & PF_NBIO) {
6027c478bd9Sstevel@tonic-gate 					if (!written)
6037c478bd9Sstevel@tonic-gate 						error = EWOULDBLOCK;
6047c478bd9Sstevel@tonic-gate 					goto out;
6057c478bd9Sstevel@tonic-gate 				}
6067c478bd9Sstevel@tonic-gate 				if (uio->uio_fmode & FNDELAY)
6077c478bd9Sstevel@tonic-gate 					goto out;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 				if (pty->pt_flags & PF_WWRITE)
6107c478bd9Sstevel@tonic-gate 					cv_broadcast(&pty->pt_cv_flags);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 				pty->pt_flags &= ~(PF_WRITE | PF_WWRITE);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 				if (!cv_wait_sig(&pty->pt_cv_readq,
6157c478bd9Sstevel@tonic-gate 				    &pty->ptc_lock)) {
6167c478bd9Sstevel@tonic-gate 					mutex_exit(&pty->ptc_lock);
6177c478bd9Sstevel@tonic-gate 					return (EINTR);
6187c478bd9Sstevel@tonic-gate 				}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 				while (pty->pt_flags & PF_WRITE) {
6217c478bd9Sstevel@tonic-gate 					pty->pt_flags |= PF_WWRITE;
6227c478bd9Sstevel@tonic-gate 					cv_wait(&pty->pt_cv_flags,
6237c478bd9Sstevel@tonic-gate 					    &pty->ptc_lock);
6247c478bd9Sstevel@tonic-gate 				}
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 				pty->pt_flags |= PF_WRITE;
6277c478bd9Sstevel@tonic-gate 			}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 			if ((pty->pt_flags & PF_NBIO) &&
6307c478bd9Sstevel@tonic-gate 			    !(uio->uio_fmode & FNONBLOCK)) {
6317c478bd9Sstevel@tonic-gate 				fmode = uio->uio_fmode;
6327c478bd9Sstevel@tonic-gate 				uio->uio_fmode |= FNONBLOCK;
6337c478bd9Sstevel@tonic-gate 			}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 			error = makemsg(uio->uio_resid, uio, pty, &mp);
6367c478bd9Sstevel@tonic-gate 			uio->uio_offset = off;
6377c478bd9Sstevel@tonic-gate 			if (fmode)
6387c478bd9Sstevel@tonic-gate 				uio->uio_fmode = fmode;
6397c478bd9Sstevel@tonic-gate 			if (error != 0) {
6407c478bd9Sstevel@tonic-gate 				if (error != EAGAIN && error != EWOULDBLOCK)
6417c478bd9Sstevel@tonic-gate 					goto out;
6427c478bd9Sstevel@tonic-gate 				if (uio->uio_fmode & FNONBLOCK) {
6437c478bd9Sstevel@tonic-gate 					if (!written)
6447c478bd9Sstevel@tonic-gate 						error = EAGAIN;
6457c478bd9Sstevel@tonic-gate 					goto out;
6467c478bd9Sstevel@tonic-gate 				}
6477c478bd9Sstevel@tonic-gate 				if (pty->pt_flags & PF_NBIO) {
6487c478bd9Sstevel@tonic-gate 					if (!written)
6497c478bd9Sstevel@tonic-gate 						error = EWOULDBLOCK;
6507c478bd9Sstevel@tonic-gate 					goto out;
6517c478bd9Sstevel@tonic-gate 				}
6527c478bd9Sstevel@tonic-gate 				if (uio->uio_fmode & FNDELAY)
6537c478bd9Sstevel@tonic-gate 					goto out;
6547c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC,
6557c478bd9Sstevel@tonic-gate 				    "ptcwrite: non null return from"
6567c478bd9Sstevel@tonic-gate 				    " makemsg");
6577c478bd9Sstevel@tonic-gate 			}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 			/*
6607c478bd9Sstevel@tonic-gate 			 * Check again for safety; since "uiomove" can take a
6617c478bd9Sstevel@tonic-gate 			 * page fault, there's no guarantee that "pt_flags"
6627c478bd9Sstevel@tonic-gate 			 * didn't change while it was happening.
6637c478bd9Sstevel@tonic-gate 			 */
6647c478bd9Sstevel@tonic-gate 			if ((q = pty->pt_ttycommon.t_readq) == NULL) {
6657c478bd9Sstevel@tonic-gate 				if (mp)
6667c478bd9Sstevel@tonic-gate 					freemsg(mp);
6677c478bd9Sstevel@tonic-gate 				error = EIO;
6687c478bd9Sstevel@tonic-gate 				goto out;
6697c478bd9Sstevel@tonic-gate 			}
6707c478bd9Sstevel@tonic-gate 			if (mp)
6717c478bd9Sstevel@tonic-gate 				(void) putq(q, mp);
6727c478bd9Sstevel@tonic-gate 			written = 1;
6737c478bd9Sstevel@tonic-gate 		} while (uio->uio_resid > 0);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate out:
6767c478bd9Sstevel@tonic-gate 	if (pty->pt_flags & PF_WWRITE)
6777c478bd9Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_flags);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	pty->pt_flags &= ~(PF_WRITE | PF_WWRITE);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
6827c478bd9Sstevel@tonic-gate 	return (error);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate #define	copy_in(data, d_arg) \
6867c478bd9Sstevel@tonic-gate 	if (copyin((caddr_t)data, &d_arg, sizeof (int)) != 0) \
6877c478bd9Sstevel@tonic-gate 		return (EFAULT)
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate #define	copy_out(d_arg, data) \
6907c478bd9Sstevel@tonic-gate 	if (copyout(&d_arg, (caddr_t)data, sizeof (int)) != 0) \
6917c478bd9Sstevel@tonic-gate 		return (EFAULT)
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate int
ptcioctl(dev_t dev,int cmd,intptr_t data,int flag,struct cred * cred,int * rvalp)6947c478bd9Sstevel@tonic-gate ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred,
6957c478bd9Sstevel@tonic-gate     int *rvalp)
6967c478bd9Sstevel@tonic-gate {
6977c478bd9Sstevel@tonic-gate 	struct pty *pty = &pty_softc[getminor(dev)];
6987c478bd9Sstevel@tonic-gate 	queue_t *q;
6997c478bd9Sstevel@tonic-gate 	struct ttysize tty_arg;
7007c478bd9Sstevel@tonic-gate 	struct winsize win_arg;
7017c478bd9Sstevel@tonic-gate 	int d_arg;
7027c478bd9Sstevel@tonic-gate 	int err;
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	switch (cmd) {
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	case TIOCPKT:
7077c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7087c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7097c478bd9Sstevel@tonic-gate 		if (d_arg) {
7107c478bd9Sstevel@tonic-gate 			if (pty->pt_flags & (PF_UCNTL|PF_43UCNTL)) {
7117c478bd9Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
7127c478bd9Sstevel@tonic-gate 				return (EINVAL);
7137c478bd9Sstevel@tonic-gate 			}
7147c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_PKT;
7157c478bd9Sstevel@tonic-gate 		} else
7167c478bd9Sstevel@tonic-gate 			pty->pt_flags &= ~PF_PKT;
7177c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7187c478bd9Sstevel@tonic-gate 		break;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	case TIOCUCNTL:
7217c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7227c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7237c478bd9Sstevel@tonic-gate 		if (d_arg) {
7247c478bd9Sstevel@tonic-gate 			if (pty->pt_flags & (PF_PKT|PF_UCNTL)) {
7257c478bd9Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
7267c478bd9Sstevel@tonic-gate 				return (EINVAL);
7277c478bd9Sstevel@tonic-gate 			}
7287c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_43UCNTL;
7297c478bd9Sstevel@tonic-gate 		} else
7307c478bd9Sstevel@tonic-gate 			pty->pt_flags &= ~PF_43UCNTL;
7317c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7327c478bd9Sstevel@tonic-gate 		break;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	case TIOCTCNTL:
7357c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7367c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7377c478bd9Sstevel@tonic-gate 		if (d_arg) {
7387c478bd9Sstevel@tonic-gate 			if (pty->pt_flags & PF_PKT) {
7397c478bd9Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
7407c478bd9Sstevel@tonic-gate 				return (EINVAL);
7417c478bd9Sstevel@tonic-gate 			}
7427c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_UCNTL;
7437c478bd9Sstevel@tonic-gate 		} else
7447c478bd9Sstevel@tonic-gate 			pty->pt_flags &= ~PF_UCNTL;
7457c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7467c478bd9Sstevel@tonic-gate 		break;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	case TIOCREMOTE:
7497c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7507c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7517c478bd9Sstevel@tonic-gate 		if (d_arg) {
7527c478bd9Sstevel@tonic-gate 			if ((q = pty->pt_ttycommon.t_readq) != NULL)
7537c478bd9Sstevel@tonic-gate 				(void) putctl1(q, M_CTL, MC_NOCANON);
7547c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_REMOTE;
7557c478bd9Sstevel@tonic-gate 		} else {
7567c478bd9Sstevel@tonic-gate 			if ((q = pty->pt_ttycommon.t_readq) != NULL)
7577c478bd9Sstevel@tonic-gate 				(void) putctl1(q, M_CTL, MC_DOCANON);
7587c478bd9Sstevel@tonic-gate 			pty->pt_flags &= ~PF_REMOTE;
7597c478bd9Sstevel@tonic-gate 		}
7607c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7617c478bd9Sstevel@tonic-gate 		break;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	case TIOCSIGNAL:
7647c478bd9Sstevel@tonic-gate 		/*
7657c478bd9Sstevel@tonic-gate 		 * Blast a M_PCSIG message up the slave stream; the
7667c478bd9Sstevel@tonic-gate 		 * signal number is the argument to the "ioctl".
7677c478bd9Sstevel@tonic-gate 		 */
7687c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7697c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7707c478bd9Sstevel@tonic-gate 		if ((q = pty->pt_ttycommon.t_readq) != NULL)
7717c478bd9Sstevel@tonic-gate 			(void) putctl1(q, M_PCSIG, (int)d_arg);
7727c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7737c478bd9Sstevel@tonic-gate 		break;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	case FIONBIO:
7767c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7777c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7787c478bd9Sstevel@tonic-gate 		if (d_arg)
7797c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_NBIO;
7807c478bd9Sstevel@tonic-gate 		else
7817c478bd9Sstevel@tonic-gate 			pty->pt_flags &= ~PF_NBIO;
7827c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7837c478bd9Sstevel@tonic-gate 		break;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	case FIOASYNC:
7867c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
7877c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
7887c478bd9Sstevel@tonic-gate 		if (d_arg)
7897c478bd9Sstevel@tonic-gate 			pty->pt_flags |= PF_ASYNC;
7907c478bd9Sstevel@tonic-gate 		else
7917c478bd9Sstevel@tonic-gate 			pty->pt_flags &= ~PF_ASYNC;
7927c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
7937c478bd9Sstevel@tonic-gate 		break;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/*
7967c478bd9Sstevel@tonic-gate 	 * These, at least, can work on the controller-side process
7977c478bd9Sstevel@tonic-gate 	 * group.
7987c478bd9Sstevel@tonic-gate 	 */
7997c478bd9Sstevel@tonic-gate 	case FIOGETOWN:
8007c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
8017c478bd9Sstevel@tonic-gate 		d_arg = -pty->pt_pgrp;
8027c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
8037c478bd9Sstevel@tonic-gate 		copy_out(d_arg, data);
8047c478bd9Sstevel@tonic-gate 		break;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	case FIOSETOWN:
8077c478bd9Sstevel@tonic-gate 		copy_in(data, d_arg);
8087c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
8097c478bd9Sstevel@tonic-gate 		pty->pt_pgrp = (short)(-d_arg);
8107c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
8117c478bd9Sstevel@tonic-gate 		break;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	case FIONREAD: {
8147c478bd9Sstevel@tonic-gate 		/*
8157c478bd9Sstevel@tonic-gate 		 * Return the total number of bytes of data in all messages
8167c478bd9Sstevel@tonic-gate 		 * in slave write queue, which is master read queue, unless a
8177c478bd9Sstevel@tonic-gate 		 * special message would be read.
8187c478bd9Sstevel@tonic-gate 		 */
8197c478bd9Sstevel@tonic-gate 		mblk_t *mp;
8207c478bd9Sstevel@tonic-gate 		size_t count = 0;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
8237c478bd9Sstevel@tonic-gate 		if (pty->pt_flags&(PF_PKT|PF_UCNTL) && pty->pt_send)
8247c478bd9Sstevel@tonic-gate 			count = 1;	/* will return 1 byte */
8257c478bd9Sstevel@tonic-gate 		else if ((pty->pt_flags & (PF_UCNTL|PF_43UCNTL)) &&
8267c478bd9Sstevel@tonic-gate 		    pty->pt_ucntl)
8277c478bd9Sstevel@tonic-gate 			count = 1;	/* will return 1 byte */
8287c478bd9Sstevel@tonic-gate 		else if ((q = pty->pt_ttycommon.t_writeq) != NULL &&
8297c478bd9Sstevel@tonic-gate 		    q->q_first != NULL && !(pty->pt_flags & PF_STOPPED)) {
8307c478bd9Sstevel@tonic-gate 			/*
8317c478bd9Sstevel@tonic-gate 			 * Will return whatever data is queued up.
8327c478bd9Sstevel@tonic-gate 			 */
8337c478bd9Sstevel@tonic-gate 			for (mp = q->q_first; mp != NULL; mp = mp->b_next)
8347c478bd9Sstevel@tonic-gate 				count += msgdsize(mp);
8357c478bd9Sstevel@tonic-gate 		} else if ((pty->pt_flags & PF_UCNTL) &&
8367c478bd9Sstevel@tonic-gate 		    pty->pt_stuffqfirst != NULL) {
8377c478bd9Sstevel@tonic-gate 			/*
8387c478bd9Sstevel@tonic-gate 			 * Will return STI'ed data.
8397c478bd9Sstevel@tonic-gate 			 */
8407c478bd9Sstevel@tonic-gate 			count = pty->pt_stuffqlen + 1;
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 		/*
8447c478bd9Sstevel@tonic-gate 		 * Under LP64 we could have more than INT_MAX bytes to report,
8457c478bd9Sstevel@tonic-gate 		 * but the interface is defined in terms of int, so we cap it.
8467c478bd9Sstevel@tonic-gate 		 */
8477c478bd9Sstevel@tonic-gate 		d_arg = MIN(count, INT_MAX);
8487c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
8497c478bd9Sstevel@tonic-gate 		copy_out(d_arg, data);
8507c478bd9Sstevel@tonic-gate 		break;
8517c478bd9Sstevel@tonic-gate 	}
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	case TIOCSWINSZ:
8547c478bd9Sstevel@tonic-gate 		/*
8557c478bd9Sstevel@tonic-gate 		 * Unfortunately, TIOCSWINSZ and the old TIOCSSIZE "ioctl"s
8567c478bd9Sstevel@tonic-gate 		 * share the same code.  If the upper 16 bits of the number
8577c478bd9Sstevel@tonic-gate 		 * of lines is non-zero, it was probably a TIOCSWINSZ,
8587c478bd9Sstevel@tonic-gate 		 * with both "ws_row" and "ws_col" non-zero.
8597c478bd9Sstevel@tonic-gate 		 */
8607c478bd9Sstevel@tonic-gate 		if (copyin((caddr_t)data,
8617c478bd9Sstevel@tonic-gate 		    &tty_arg, sizeof (struct ttysize)) != 0)
8627c478bd9Sstevel@tonic-gate 			return (EFAULT);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		if ((tty_arg.ts_lines & 0xffff0000) != 0) {
8657c478bd9Sstevel@tonic-gate 			/*
8667c478bd9Sstevel@tonic-gate 			 * It's a TIOCSWINSZ.
8677c478bd9Sstevel@tonic-gate 			 */
8687c478bd9Sstevel@tonic-gate 			win_arg = *(struct winsize *)&tty_arg;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 			mutex_enter(&pty->ptc_lock);
8717c478bd9Sstevel@tonic-gate 			/*
8727c478bd9Sstevel@tonic-gate 			 * If the window size changed, send a SIGWINCH.
8737c478bd9Sstevel@tonic-gate 			 */
8747c478bd9Sstevel@tonic-gate 			if (bcmp(&pty->pt_ttycommon.t_size,
8757c478bd9Sstevel@tonic-gate 			    &win_arg, sizeof (struct winsize))) {
8767c478bd9Sstevel@tonic-gate 				pty->pt_ttycommon.t_size = win_arg;
8777c478bd9Sstevel@tonic-gate 				if ((q = pty->pt_ttycommon.t_readq) != NULL)
8787c478bd9Sstevel@tonic-gate 					(void) putctl1(q, M_PCSIG, SIGWINCH);
8797c478bd9Sstevel@tonic-gate 			}
8807c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
8817c478bd9Sstevel@tonic-gate 			break;
8827c478bd9Sstevel@tonic-gate 		}
8837c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	case TIOCSSIZE:
8867c478bd9Sstevel@tonic-gate 		if (copyin((caddr_t)data,
8877c478bd9Sstevel@tonic-gate 		    &tty_arg, sizeof (struct ttysize)) != 0)
8887c478bd9Sstevel@tonic-gate 			return (EFAULT);
8897c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
8907c478bd9Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_row = (ushort_t)tty_arg.ts_lines;
8917c478bd9Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_col = (ushort_t)tty_arg.ts_cols;
8927c478bd9Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_xpixel = 0;
8937c478bd9Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_ypixel = 0;
8947c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
8957c478bd9Sstevel@tonic-gate 		break;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	case TIOCGWINSZ:
8987c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
8997c478bd9Sstevel@tonic-gate 		win_arg = pty->pt_ttycommon.t_size;
9007c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
9017c478bd9Sstevel@tonic-gate 		if (copyout(&win_arg, (caddr_t)data,
9027c478bd9Sstevel@tonic-gate 		    sizeof (struct winsize)) != 0)
9037c478bd9Sstevel@tonic-gate 			return (EFAULT);
9047c478bd9Sstevel@tonic-gate 		break;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	case TIOCGSIZE:
9077c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
9087c478bd9Sstevel@tonic-gate 		tty_arg.ts_lines = pty->pt_ttycommon.t_size.ws_row;
9097c478bd9Sstevel@tonic-gate 		tty_arg.ts_cols = pty->pt_ttycommon.t_size.ws_col;
9107c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
9117c478bd9Sstevel@tonic-gate 		if (copyout(&tty_arg, (caddr_t)data,
9127c478bd9Sstevel@tonic-gate 		    sizeof (struct ttysize)) != 0)
9137c478bd9Sstevel@tonic-gate 			return (EFAULT);
9147c478bd9Sstevel@tonic-gate 		break;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/*
9177c478bd9Sstevel@tonic-gate 	 * XXX These should not be here.  The only reason why an
9187c478bd9Sstevel@tonic-gate 	 * "ioctl" on the controller side should get the
9197c478bd9Sstevel@tonic-gate 	 * slave side's process group is so that the process on
9207c478bd9Sstevel@tonic-gate 	 * the controller side can send a signal to the slave
9217c478bd9Sstevel@tonic-gate 	 * side's process group; however, this is better done
9227c478bd9Sstevel@tonic-gate 	 * with TIOCSIGNAL, both because it doesn't require us
9237c478bd9Sstevel@tonic-gate 	 * to know about the slave side's process group and because
9247c478bd9Sstevel@tonic-gate 	 * the controller side process may not have permission to
9257c478bd9Sstevel@tonic-gate 	 * send that signal to the entire process group.
9267c478bd9Sstevel@tonic-gate 	 *
9277c478bd9Sstevel@tonic-gate 	 * However, since vanilla 4BSD doesn't provide TIOCSIGNAL,
9287c478bd9Sstevel@tonic-gate 	 * we can't just get rid of them.
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate 	case TIOCGPGRP:
9317c478bd9Sstevel@tonic-gate 	case TIOCSPGRP:
9327c478bd9Sstevel@tonic-gate 	/*
9337c478bd9Sstevel@tonic-gate 	 * This is amazingly disgusting, but the stupid semantics of
9347c478bd9Sstevel@tonic-gate 	 * 4BSD pseudo-ttys makes us do it.  If we do one of these guys
9357c478bd9Sstevel@tonic-gate 	 * on the controller side, it really applies to the slave-side
9367c478bd9Sstevel@tonic-gate 	 * stream.  It should NEVER have been possible to do ANY sort
9377c478bd9Sstevel@tonic-gate 	 * of tty operations on the controller side, but it's too late
9387c478bd9Sstevel@tonic-gate 	 * to fix that now.  However, we won't waste our time implementing
9397c478bd9Sstevel@tonic-gate 	 * anything that the original pseudo-tty driver didn't handle.
9407c478bd9Sstevel@tonic-gate 	 */
9417c478bd9Sstevel@tonic-gate 	case TIOCGETP:
9427c478bd9Sstevel@tonic-gate 	case TIOCSETP:
9437c478bd9Sstevel@tonic-gate 	case TIOCSETN:
9447c478bd9Sstevel@tonic-gate 	case TIOCGETC:
9457c478bd9Sstevel@tonic-gate 	case TIOCSETC:
9467c478bd9Sstevel@tonic-gate 	case TIOCGLTC:
9477c478bd9Sstevel@tonic-gate 	case TIOCSLTC:
9487c478bd9Sstevel@tonic-gate 	case TIOCLGET:
9497c478bd9Sstevel@tonic-gate 	case TIOCLSET:
9507c478bd9Sstevel@tonic-gate 	case TIOCLBIS:
9517c478bd9Sstevel@tonic-gate 	case TIOCLBIC:
9527c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
9537c478bd9Sstevel@tonic-gate 		if (pty->pt_vnode == NULL) {
9547c478bd9Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
9557c478bd9Sstevel@tonic-gate 			return (EIO);
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 		pty->pt_flags |= PF_IOCTL;
9587c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
9597c478bd9Sstevel@tonic-gate 		err = strioctl(pty->pt_vnode, cmd, data, flag,
9607c478bd9Sstevel@tonic-gate 		    U_TO_K, cred, rvalp);
9617c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
9627c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & PF_WAIT)
9637c478bd9Sstevel@tonic-gate 			cv_signal(&pty->pt_cv_flags);
9647c478bd9Sstevel@tonic-gate 		pty->pt_flags &= ~(PF_IOCTL|PF_WAIT);
9657c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
9667c478bd9Sstevel@tonic-gate 		return (err);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	default:
9697c478bd9Sstevel@tonic-gate 		return (ENOTTY);
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	return (0);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate int
ptcpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)9777c478bd9Sstevel@tonic-gate ptcpoll(dev_t dev,
9787c478bd9Sstevel@tonic-gate 	short events,
9797c478bd9Sstevel@tonic-gate 	int anyyet,
9807c478bd9Sstevel@tonic-gate 	short *reventsp,
9817c478bd9Sstevel@tonic-gate 	struct pollhead **phpp)
9827c478bd9Sstevel@tonic-gate {
9837c478bd9Sstevel@tonic-gate 	struct pty *pty = &pty_softc[getminor(dev)];
9847c478bd9Sstevel@tonic-gate 	pollhead_t *php = &ptcph;
9857c478bd9Sstevel@tonic-gate 	queue_t *q;
9867c478bd9Sstevel@tonic-gate 	int pos = 0;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate #ifdef lint
9897c478bd9Sstevel@tonic-gate 	anyyet = anyyet;
9907c478bd9Sstevel@tonic-gate #endif
9917c478bd9Sstevel@tonic-gate 	polllock(php, &pty->ptc_lock);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pty->ptc_lock));
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	*reventsp = 0;
9967c478bd9Sstevel@tonic-gate 	if (pty->pt_flags & PF_SLAVEGONE) {
9977c478bd9Sstevel@tonic-gate 		if (events & (POLLIN|POLLRDNORM))
9987c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLIN|POLLRDNORM));
9997c478bd9Sstevel@tonic-gate 		if (events & (POLLOUT|POLLWRNORM))
10007c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLOUT|POLLWRNORM));
10017c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
10027c478bd9Sstevel@tonic-gate 		/*
10037c478bd9Sstevel@tonic-gate 		 * A non NULL pollhead pointer should be returned in case
10047c478bd9Sstevel@tonic-gate 		 * user polls for 0 events.
10057c478bd9Sstevel@tonic-gate 		 */
10067c478bd9Sstevel@tonic-gate 		*phpp = !anyyet && !*reventsp ? php : (struct pollhead *)NULL;
10077c478bd9Sstevel@tonic-gate 		return (0);
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 	if (events & (POLLIN|POLLRDNORM)) {
10107c478bd9Sstevel@tonic-gate 		if ((q = pty->pt_ttycommon.t_writeq) != NULL &&
10117c478bd9Sstevel@tonic-gate 		    q->q_first != NULL && !(pty->pt_flags & PF_STOPPED)) {
10127c478bd9Sstevel@tonic-gate 			/*
10137c478bd9Sstevel@tonic-gate 			 * Regular data is available.
10147c478bd9Sstevel@tonic-gate 			 */
10157c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLIN|POLLRDNORM));
10167c478bd9Sstevel@tonic-gate 			pos++;
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 		if (pty->pt_flags & (PF_PKT|PF_UCNTL) && pty->pt_send) {
10197c478bd9Sstevel@tonic-gate 			/*
10207c478bd9Sstevel@tonic-gate 			 * A control packet is available.
10217c478bd9Sstevel@tonic-gate 			 */
10227c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLIN|POLLRDNORM));
10237c478bd9Sstevel@tonic-gate 			pos++;
10247c478bd9Sstevel@tonic-gate 		}
10257c478bd9Sstevel@tonic-gate 		if ((pty->pt_flags & PF_UCNTL) &&
10267c478bd9Sstevel@tonic-gate 		    (pty->pt_ucntl || pty->pt_stuffqfirst != NULL)) {
10277c478bd9Sstevel@tonic-gate 			/*
10287c478bd9Sstevel@tonic-gate 			 * "ioctl" or TIOCSTI data is available.
10297c478bd9Sstevel@tonic-gate 			 */
10307c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLIN|POLLRDNORM));
10317c478bd9Sstevel@tonic-gate 			pos++;
10327c478bd9Sstevel@tonic-gate 		}
10337c478bd9Sstevel@tonic-gate 		if ((pty->pt_flags & PF_43UCNTL) && pty->pt_ucntl) {
10347c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLIN|POLLRDNORM));
10357c478bd9Sstevel@tonic-gate 			pos++;
10367c478bd9Sstevel@tonic-gate 		}
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 	if (events & (POLLOUT|POLLWRNORM)) {
10397c478bd9Sstevel@tonic-gate 		if ((q = pty->pt_ttycommon.t_readq) != NULL &&
10407c478bd9Sstevel@tonic-gate 		    canput(q)) {
10417c478bd9Sstevel@tonic-gate 			*reventsp |= (events & (POLLOUT|POLLWRNORM));
10427c478bd9Sstevel@tonic-gate 			pos++;
10437c478bd9Sstevel@tonic-gate 		}
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 	if (events & POLLERR) {
10467c478bd9Sstevel@tonic-gate 		*reventsp |= POLLERR;
10477c478bd9Sstevel@tonic-gate 		pos++;
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 	if (events == 0) {	/* "exceptional conditions" */
10507c478bd9Sstevel@tonic-gate 		if (((pty->pt_flags & (PF_PKT|PF_UCNTL)) && pty->pt_send) ||
10517c478bd9Sstevel@tonic-gate 		    ((pty->pt_flags & PF_UCNTL) &&
10527c478bd9Sstevel@tonic-gate 		    (pty->pt_ucntl || pty->pt_stuffqfirst != NULL))) {
10537c478bd9Sstevel@tonic-gate 			pos++;
10547c478bd9Sstevel@tonic-gate 		}
10557c478bd9Sstevel@tonic-gate 		if ((pty->pt_flags & PF_43UCNTL) && pty->pt_ucntl) {
10567c478bd9Sstevel@tonic-gate 			pos++;
10577c478bd9Sstevel@tonic-gate 		}
10587c478bd9Sstevel@tonic-gate 	}
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	/*
10617c478bd9Sstevel@tonic-gate 	 * Arrange to have poll waken up when event occurs.
10627c478bd9Sstevel@tonic-gate 	 * if (!anyyet)
10637c478bd9Sstevel@tonic-gate 	 */
10647c478bd9Sstevel@tonic-gate 	if (!pos) {
10657c478bd9Sstevel@tonic-gate 		*phpp = php;
10667c478bd9Sstevel@tonic-gate 		*reventsp = 0;
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
10707c478bd9Sstevel@tonic-gate 	return (0);
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate void
gsignal(int pid,int sig)10747c478bd9Sstevel@tonic-gate gsignal(int pid, int sig)
10757c478bd9Sstevel@tonic-gate {
10767c478bd9Sstevel@tonic-gate 	procset_t set;
10777c478bd9Sstevel@tonic-gate 	sigsend_t v;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	bzero(&v, sizeof (v));
10807c478bd9Sstevel@tonic-gate 	v.sig = sig;
10817c478bd9Sstevel@tonic-gate 	v.perm = 0;
10827c478bd9Sstevel@tonic-gate 	v.checkperm = 1;
10837c478bd9Sstevel@tonic-gate 	v.value.sival_ptr = NULL;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	setprocset(&set, POP_AND, P_PGID, -pid, P_ALL, P_MYID);
10867c478bd9Sstevel@tonic-gate 	(void) sigsendset(&set, &v);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate static int
makemsg(ssize_t count,struct uio * uiop,struct pty * pty,mblk_t ** mpp)10907c478bd9Sstevel@tonic-gate makemsg(ssize_t count, struct uio *uiop, struct pty *pty, mblk_t **mpp)
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate 	int pri = BPRI_LO;
10937c478bd9Sstevel@tonic-gate 	int error;
10947c478bd9Sstevel@tonic-gate 	mblk_t *bp = NULL;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pty->ptc_lock));
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	*mpp = NULL;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	/*
11017c478bd9Sstevel@tonic-gate 	 * Create data part of message, if any.
11027c478bd9Sstevel@tonic-gate 	 */
11037c478bd9Sstevel@tonic-gate 	if (count >= 0) {
11047c478bd9Sstevel@tonic-gate 		if ((bp = allocb(count, pri)) == NULL)
11057c478bd9Sstevel@tonic-gate 			return (ENOSR);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
11087c478bd9Sstevel@tonic-gate 		error = uiomove((caddr_t)bp->b_wptr, count, UIO_WRITE, uiop);
11097c478bd9Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
11107c478bd9Sstevel@tonic-gate 		if (error) {
11117c478bd9Sstevel@tonic-gate 			freeb(bp);
11127c478bd9Sstevel@tonic-gate 			return (error);
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 		bp->b_wptr += count;
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	*mpp = bp;
11197c478bd9Sstevel@tonic-gate 	return (0);
11207c478bd9Sstevel@tonic-gate }
1121