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