1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* 7*0Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 8*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 9*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 10*0Sstevel@tonic-gate */ 11*0Sstevel@tonic-gate 12*0Sstevel@tonic-gate /* 13*0Sstevel@tonic-gate * PTY - Stream "pseudo-tty" device. For each "controller" side 14*0Sstevel@tonic-gate * it connects to a "slave" side. 15*0Sstevel@tonic-gate */ 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 18*0Sstevel@tonic-gate 19*0Sstevel@tonic-gate #include <sys/param.h> 20*0Sstevel@tonic-gate #include <sys/systm.h> 21*0Sstevel@tonic-gate #include <sys/filio.h> 22*0Sstevel@tonic-gate #include <sys/ioccom.h> 23*0Sstevel@tonic-gate #include <sys/termios.h> 24*0Sstevel@tonic-gate #include <sys/termio.h> 25*0Sstevel@tonic-gate #include <sys/ttold.h> 26*0Sstevel@tonic-gate #include <sys/stropts.h> 27*0Sstevel@tonic-gate #include <sys/stream.h> 28*0Sstevel@tonic-gate #include <sys/tty.h> 29*0Sstevel@tonic-gate #include <sys/user.h> 30*0Sstevel@tonic-gate #include <sys/conf.h> 31*0Sstevel@tonic-gate #include <sys/file.h> 32*0Sstevel@tonic-gate #include <sys/vnode.h> /* 1/0 on the vomit meter */ 33*0Sstevel@tonic-gate #include <sys/proc.h> 34*0Sstevel@tonic-gate #include <sys/uio.h> 35*0Sstevel@tonic-gate #include <sys/errno.h> 36*0Sstevel@tonic-gate #include <sys/strsubr.h> 37*0Sstevel@tonic-gate #include <sys/poll.h> 38*0Sstevel@tonic-gate #include <sys/sysmacros.h> 39*0Sstevel@tonic-gate #include <sys/debug.h> 40*0Sstevel@tonic-gate #include <sys/procset.h> 41*0Sstevel@tonic-gate #include <sys/cred.h> 42*0Sstevel@tonic-gate #include <sys/ptyvar.h> 43*0Sstevel@tonic-gate #include <sys/suntty.h> 44*0Sstevel@tonic-gate #include <sys/stat.h> 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #include <sys/conf.h> 47*0Sstevel@tonic-gate #include <sys/ddi.h> 48*0Sstevel@tonic-gate #include <sys/sunddi.h> 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate extern int npty; /* number of pseudo-ttys configured in */ 51*0Sstevel@tonic-gate extern struct pty *pty_softc; 52*0Sstevel@tonic-gate extern struct pollhead ptcph; /* poll head for ptcpoll() use */ 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate int ptcopen(dev_t *, int, int, struct cred *); 55*0Sstevel@tonic-gate int ptcclose(dev_t, int, int, struct cred *); 56*0Sstevel@tonic-gate int ptcwrite(dev_t, struct uio *, struct cred *); 57*0Sstevel@tonic-gate int ptcread(dev_t, struct uio *, struct cred *); 58*0Sstevel@tonic-gate int ptcioctl(dev_t, int, intptr_t, int, struct cred *, int *); 59*0Sstevel@tonic-gate int ptcpoll(dev_t, short, int, short *, struct pollhead **); 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate static int ptc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 62*0Sstevel@tonic-gate static int ptc_attach(dev_info_t *, ddi_attach_cmd_t); 63*0Sstevel@tonic-gate static dev_info_t *ptc_dip; /* for dev-to-dip conversions */ 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static void ptc_init(void), ptc_uninit(void); 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate static int makemsg(ssize_t count, struct uio *uiop, 68*0Sstevel@tonic-gate struct pty *pty, mblk_t **mpp); 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate struct cb_ops ptc_cb_ops = { 71*0Sstevel@tonic-gate ptcopen, /* open */ 72*0Sstevel@tonic-gate ptcclose, /* close */ 73*0Sstevel@tonic-gate nodev, /* strategy */ 74*0Sstevel@tonic-gate nodev, /* print */ 75*0Sstevel@tonic-gate nodev, /* dump */ 76*0Sstevel@tonic-gate ptcread, /* read */ 77*0Sstevel@tonic-gate ptcwrite, /* write */ 78*0Sstevel@tonic-gate ptcioctl, /* ioctl */ 79*0Sstevel@tonic-gate nodev, /* devmap */ 80*0Sstevel@tonic-gate nodev, /* mmap */ 81*0Sstevel@tonic-gate nodev, /* segmap */ 82*0Sstevel@tonic-gate ptcpoll, /* poll */ 83*0Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 84*0Sstevel@tonic-gate 0, /* streamtab */ 85*0Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 86*0Sstevel@tonic-gate }; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate struct dev_ops ptc_ops = { 89*0Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 90*0Sstevel@tonic-gate 0, /* refcnt */ 91*0Sstevel@tonic-gate ptc_info, /* info */ 92*0Sstevel@tonic-gate nulldev, /* identify */ 93*0Sstevel@tonic-gate nulldev, /* probe */ 94*0Sstevel@tonic-gate ptc_attach, /* attach */ 95*0Sstevel@tonic-gate nodev, /* detach */ 96*0Sstevel@tonic-gate nodev, /* reset */ 97*0Sstevel@tonic-gate &ptc_cb_ops, /* driver operations */ 98*0Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations */ 99*0Sstevel@tonic-gate }; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate #include <sys/types.h> 102*0Sstevel@tonic-gate #include <sys/conf.h> 103*0Sstevel@tonic-gate #include <sys/param.h> 104*0Sstevel@tonic-gate #include <sys/systm.h> 105*0Sstevel@tonic-gate #include <sys/errno.h> 106*0Sstevel@tonic-gate #include <sys/modctl.h> 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate extern int dseekneg_flag; 109*0Sstevel@tonic-gate extern struct mod_ops mod_driverops; 110*0Sstevel@tonic-gate extern struct dev_ops ptc_ops; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate /* 113*0Sstevel@tonic-gate * Module linkage information for the kernel. 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate static struct modldrv modldrv = { 117*0Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 118*0Sstevel@tonic-gate "tty pseudo driver control 'ptc' %I%", 119*0Sstevel@tonic-gate &ptc_ops, /* driver ops */ 120*0Sstevel@tonic-gate }; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 123*0Sstevel@tonic-gate MODREV_1, 124*0Sstevel@tonic-gate &modldrv, 125*0Sstevel@tonic-gate NULL 126*0Sstevel@tonic-gate }; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate int 129*0Sstevel@tonic-gate _init() 130*0Sstevel@tonic-gate { 131*0Sstevel@tonic-gate int rc; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate if ((rc = mod_install(&modlinkage)) == 0) 134*0Sstevel@tonic-gate ptc_init(); 135*0Sstevel@tonic-gate return (rc); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate int 140*0Sstevel@tonic-gate _fini() 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate int rc; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate if ((rc = mod_remove(&modlinkage)) == 0) 145*0Sstevel@tonic-gate ptc_uninit(); 146*0Sstevel@tonic-gate return (rc); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate int 150*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 151*0Sstevel@tonic-gate { 152*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate static char *pty_banks = PTY_BANKS; 156*0Sstevel@tonic-gate static char *pty_digits = PTY_DIGITS; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* ARGSUSED */ 159*0Sstevel@tonic-gate static int 160*0Sstevel@tonic-gate ptc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 161*0Sstevel@tonic-gate { 162*0Sstevel@tonic-gate char name[8]; 163*0Sstevel@tonic-gate int pty_num; 164*0Sstevel@tonic-gate char *pty_digit = pty_digits; 165*0Sstevel@tonic-gate char *pty_bank = pty_banks; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate for (pty_num = 0; pty_num < npty; pty_num++) { 168*0Sstevel@tonic-gate (void) sprintf(name, "pty%c%c", *pty_bank, *pty_digit); 169*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, name, S_IFCHR, 170*0Sstevel@tonic-gate pty_num, DDI_PSEUDO, NULL) == DDI_FAILURE) { 171*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 172*0Sstevel@tonic-gate return (-1); 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate if (*(++pty_digit) == '\0') { 175*0Sstevel@tonic-gate pty_digit = pty_digits; 176*0Sstevel@tonic-gate if (*(++pty_bank) == '\0') 177*0Sstevel@tonic-gate break; 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate ptc_dip = devi; 181*0Sstevel@tonic-gate return (DDI_SUCCESS); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* ARGSUSED */ 185*0Sstevel@tonic-gate static int 186*0Sstevel@tonic-gate ptc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 187*0Sstevel@tonic-gate { 188*0Sstevel@tonic-gate int error; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate switch (infocmd) { 191*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 192*0Sstevel@tonic-gate if (ptc_dip == NULL) { 193*0Sstevel@tonic-gate *result = (void *)NULL; 194*0Sstevel@tonic-gate error = DDI_FAILURE; 195*0Sstevel@tonic-gate } else { 196*0Sstevel@tonic-gate *result = (void *) ptc_dip; 197*0Sstevel@tonic-gate error = DDI_SUCCESS; 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate break; 200*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 201*0Sstevel@tonic-gate *result = (void *)0; 202*0Sstevel@tonic-gate error = DDI_SUCCESS; 203*0Sstevel@tonic-gate break; 204*0Sstevel@tonic-gate default: 205*0Sstevel@tonic-gate error = DDI_FAILURE; 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate return (error); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate static void 211*0Sstevel@tonic-gate ptc_init(void) 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate minor_t dev; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate for (dev = 0; dev < npty; dev++) { 216*0Sstevel@tonic-gate cv_init(&pty_softc[dev].pt_cv_flags, NULL, CV_DEFAULT, NULL); 217*0Sstevel@tonic-gate cv_init(&pty_softc[dev].pt_cv_readq, NULL, CV_DEFAULT, NULL); 218*0Sstevel@tonic-gate cv_init(&pty_softc[dev].pt_cv_writeq, NULL, CV_DEFAULT, NULL); 219*0Sstevel@tonic-gate mutex_init(&pty_softc[dev].ptc_lock, NULL, MUTEX_DEFAULT, NULL); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate static void 224*0Sstevel@tonic-gate ptc_uninit(void) 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate minor_t dev; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate for (dev = 0; dev < npty; dev++) { 229*0Sstevel@tonic-gate cv_destroy(&pty_softc[dev].pt_cv_flags); 230*0Sstevel@tonic-gate cv_destroy(&pty_softc[dev].pt_cv_readq); 231*0Sstevel@tonic-gate cv_destroy(&pty_softc[dev].pt_cv_writeq); 232*0Sstevel@tonic-gate mutex_destroy(&pty_softc[dev].ptc_lock); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate } 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* 237*0Sstevel@tonic-gate * Controller side. This is not, alas, a streams device; there are too 238*0Sstevel@tonic-gate * many old features that we must support and that don't work well 239*0Sstevel@tonic-gate * with streams. 240*0Sstevel@tonic-gate */ 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /*ARGSUSED*/ 243*0Sstevel@tonic-gate int 244*0Sstevel@tonic-gate ptcopen(dev_t *devp, int flag, int otyp, struct cred *cred) 245*0Sstevel@tonic-gate { 246*0Sstevel@tonic-gate dev_t dev = *devp; 247*0Sstevel@tonic-gate struct pty *pty; 248*0Sstevel@tonic-gate queue_t *q; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (getminor(dev) >= npty) { 251*0Sstevel@tonic-gate return (ENXIO); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate pty = &pty_softc[getminor(dev)]; 254*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 255*0Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 256*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 257*0Sstevel@tonic-gate return (EIO); /* controller is exclusive use */ 258*0Sstevel@tonic-gate /* XXX - should be EBUSY! */ 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate if (pty->pt_flags & PF_WOPEN) { 261*0Sstevel@tonic-gate pty->pt_flags &= ~PF_WOPEN; 262*0Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL) { 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * Send an un-hangup to the slave, since "carrier" is 268*0Sstevel@tonic-gate * coming back up. Make sure we're doing canonicalization. 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate (void) putctl(q, M_UNHANGUP); 271*0Sstevel@tonic-gate (void) putctl1(q, M_CTL, MC_DOCANON); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate pty->pt_flags |= PF_CARR_ON; 274*0Sstevel@tonic-gate pty->pt_send = 0; 275*0Sstevel@tonic-gate pty->pt_ucntl = 0; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 278*0Sstevel@tonic-gate return (0); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate /*ARGSUSED1*/ 282*0Sstevel@tonic-gate int 283*0Sstevel@tonic-gate ptcclose(dev_t dev, int flag, int otyp, struct cred *cred) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate struct pty *pty; 286*0Sstevel@tonic-gate mblk_t *bp; 287*0Sstevel@tonic-gate queue_t *q; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate pty = &pty_softc[getminor(dev)]; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 292*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL) { 293*0Sstevel@tonic-gate /* 294*0Sstevel@tonic-gate * Send a hangup to the slave, since "carrier" is dropping. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate (void) putctl(q, M_HANGUP); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate /* 300*0Sstevel@tonic-gate * Clear out all the controller-side state. This also 301*0Sstevel@tonic-gate * clears PF_CARR_ON, which is correct because the 302*0Sstevel@tonic-gate * "carrier" is dropping since the controller process 303*0Sstevel@tonic-gate * is going away. 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate pty->pt_flags &= (PF_WOPEN|PF_STOPPED|PF_NOSTOP); 306*0Sstevel@tonic-gate while ((bp = pty->pt_stuffqfirst) != NULL) { 307*0Sstevel@tonic-gate if ((pty->pt_stuffqfirst = bp->b_next) == NULL) 308*0Sstevel@tonic-gate pty->pt_stuffqlast = NULL; 309*0Sstevel@tonic-gate else 310*0Sstevel@tonic-gate pty->pt_stuffqfirst->b_prev = NULL; 311*0Sstevel@tonic-gate pty->pt_stuffqlen--; 312*0Sstevel@tonic-gate bp->b_next = bp->b_prev = NULL; 313*0Sstevel@tonic-gate freemsg(bp); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 316*0Sstevel@tonic-gate return (0); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate int 320*0Sstevel@tonic-gate ptcread(dev_t dev, struct uio *uio, struct cred *cred) 321*0Sstevel@tonic-gate { 322*0Sstevel@tonic-gate struct pty *pty = &pty_softc[getminor(dev)]; 323*0Sstevel@tonic-gate mblk_t *bp, *nbp; 324*0Sstevel@tonic-gate queue_t *q; 325*0Sstevel@tonic-gate unsigned char tmp; 326*0Sstevel@tonic-gate ssize_t cc; 327*0Sstevel@tonic-gate int error; 328*0Sstevel@tonic-gate off_t off; 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate #ifdef lint 331*0Sstevel@tonic-gate cred = cred; 332*0Sstevel@tonic-gate #endif 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate off = uio->uio_offset; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate for (;;) { 339*0Sstevel@tonic-gate while (pty->pt_flags & PF_READ) { 340*0Sstevel@tonic-gate pty->pt_flags |= PF_WREAD; 341*0Sstevel@tonic-gate cv_wait(&pty->pt_cv_flags, &pty->ptc_lock); 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate pty->pt_flags |= PF_READ; 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* 346*0Sstevel@tonic-gate * If there's a TIOCPKT packet waiting, pass it back. 347*0Sstevel@tonic-gate */ 348*0Sstevel@tonic-gate while (pty->pt_flags&(PF_PKT|PF_UCNTL) && pty->pt_send) { 349*0Sstevel@tonic-gate tmp = pty->pt_send; 350*0Sstevel@tonic-gate pty->pt_send = 0; 351*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 352*0Sstevel@tonic-gate error = ureadc((int)tmp, uio); 353*0Sstevel@tonic-gate uio->uio_offset = off; 354*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 355*0Sstevel@tonic-gate if (error) { 356*0Sstevel@tonic-gate pty->pt_send |= tmp; 357*0Sstevel@tonic-gate goto out; 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate if (pty->pt_send == 0) 360*0Sstevel@tonic-gate goto out; 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * If there's a user-control packet waiting, pass the 365*0Sstevel@tonic-gate * "ioctl" code back. 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate while ((pty->pt_flags & (PF_UCNTL|PF_43UCNTL)) && 368*0Sstevel@tonic-gate pty->pt_ucntl) { 369*0Sstevel@tonic-gate tmp = pty->pt_ucntl; 370*0Sstevel@tonic-gate pty->pt_ucntl = 0; 371*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 372*0Sstevel@tonic-gate error = ureadc((int)tmp, uio); 373*0Sstevel@tonic-gate uio->uio_offset = off; 374*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 375*0Sstevel@tonic-gate if (error) { 376*0Sstevel@tonic-gate if (pty->pt_ucntl == 0) 377*0Sstevel@tonic-gate pty->pt_ucntl = tmp; 378*0Sstevel@tonic-gate goto out; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate if (pty->pt_ucntl == 0) 381*0Sstevel@tonic-gate goto out; 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * If there's any data waiting, pass it back. 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_writeq) != NULL && 388*0Sstevel@tonic-gate q->q_first != NULL && 389*0Sstevel@tonic-gate !(pty->pt_flags & PF_STOPPED)) { 390*0Sstevel@tonic-gate if (pty->pt_flags & (PF_PKT|PF_UCNTL|PF_43UCNTL)) { 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * We're about to begin a move in packet or 393*0Sstevel@tonic-gate * user-control mode; precede the data with a 394*0Sstevel@tonic-gate * data header. 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 397*0Sstevel@tonic-gate error = ureadc(TIOCPKT_DATA, uio); 398*0Sstevel@tonic-gate uio->uio_offset = off; 399*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 400*0Sstevel@tonic-gate if (error != 0) 401*0Sstevel@tonic-gate goto out; 402*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_writeq) == NULL) 403*0Sstevel@tonic-gate goto out; 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate if ((bp = getq(q)) == NULL) 406*0Sstevel@tonic-gate goto out; 407*0Sstevel@tonic-gate while (uio->uio_resid > 0) { 408*0Sstevel@tonic-gate while ((cc = bp->b_wptr - bp->b_rptr) == 0) { 409*0Sstevel@tonic-gate nbp = bp->b_cont; 410*0Sstevel@tonic-gate freeb(bp); 411*0Sstevel@tonic-gate if ((bp = nbp) == NULL) { 412*0Sstevel@tonic-gate if ((q == NULL) || 413*0Sstevel@tonic-gate (bp = getq(q)) == NULL) 414*0Sstevel@tonic-gate goto out; 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate cc = MIN(cc, uio->uio_resid); 418*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 419*0Sstevel@tonic-gate error = uiomove((caddr_t)bp->b_rptr, 420*0Sstevel@tonic-gate cc, UIO_READ, uio); 421*0Sstevel@tonic-gate uio->uio_offset = off; 422*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 423*0Sstevel@tonic-gate if (error != 0) { 424*0Sstevel@tonic-gate freemsg(bp); 425*0Sstevel@tonic-gate goto out; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate q = pty->pt_ttycommon.t_writeq; 428*0Sstevel@tonic-gate bp->b_rptr += cc; 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * Strip off zero-length blocks from the front of 432*0Sstevel@tonic-gate * what we're putting back on the queue. 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate while ((bp->b_wptr - bp->b_rptr) == 0) { 435*0Sstevel@tonic-gate nbp = bp->b_cont; 436*0Sstevel@tonic-gate freeb(bp); 437*0Sstevel@tonic-gate if ((bp = nbp) == NULL) 438*0Sstevel@tonic-gate goto out; /* nothing left */ 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate if (q != NULL) 441*0Sstevel@tonic-gate (void) putbq(q, bp); 442*0Sstevel@tonic-gate else 443*0Sstevel@tonic-gate freemsg(bp); 444*0Sstevel@tonic-gate goto out; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * If there's any TIOCSTI-stuffed characters, pass 449*0Sstevel@tonic-gate * them back. (They currently arrive after all output; 450*0Sstevel@tonic-gate * is this correct?) 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate if (pty->pt_flags&PF_UCNTL && pty->pt_stuffqfirst != NULL) { 453*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 454*0Sstevel@tonic-gate error = ureadc(TIOCSTI&0xff, uio); 455*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 456*0Sstevel@tonic-gate while (error == 0 && 457*0Sstevel@tonic-gate (bp = pty->pt_stuffqfirst) != NULL && 458*0Sstevel@tonic-gate uio->uio_resid > 0) { 459*0Sstevel@tonic-gate pty->pt_stuffqlen--; 460*0Sstevel@tonic-gate if ((pty->pt_stuffqfirst = bp->b_next) == NULL) 461*0Sstevel@tonic-gate pty->pt_stuffqlast = NULL; 462*0Sstevel@tonic-gate else 463*0Sstevel@tonic-gate pty->pt_stuffqfirst->b_prev = NULL; 464*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 465*0Sstevel@tonic-gate error = ureadc((int)*bp->b_rptr, uio); 466*0Sstevel@tonic-gate bp->b_next = bp->b_prev = NULL; 467*0Sstevel@tonic-gate freemsg(bp); 468*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate uio->uio_offset = off; 471*0Sstevel@tonic-gate goto out; 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate /* 475*0Sstevel@tonic-gate * There's no data available. 476*0Sstevel@tonic-gate * We want to block until the slave is open, and there's 477*0Sstevel@tonic-gate * something to read; but if we lost the slave or we're NBIO, 478*0Sstevel@tonic-gate * then return the appropriate error instead. POSIX-style 479*0Sstevel@tonic-gate * non-block has top billing and gives -1 with errno = EAGAIN, 480*0Sstevel@tonic-gate * BSD-style comes next and gives -1 with errno = EWOULDBLOCK, 481*0Sstevel@tonic-gate * SVID-style comes last and gives 0. 482*0Sstevel@tonic-gate */ 483*0Sstevel@tonic-gate if (pty->pt_flags & PF_SLAVEGONE) { 484*0Sstevel@tonic-gate error = EIO; 485*0Sstevel@tonic-gate goto out; 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate if (uio->uio_fmode & FNONBLOCK) { 488*0Sstevel@tonic-gate error = EAGAIN; 489*0Sstevel@tonic-gate goto out; 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate if (pty->pt_flags & PF_NBIO) { 492*0Sstevel@tonic-gate error = EWOULDBLOCK; 493*0Sstevel@tonic-gate goto out; 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate if (uio->uio_fmode & FNDELAY) 496*0Sstevel@tonic-gate goto out; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate if (pty->pt_flags & PF_WREAD) 499*0Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate pty->pt_flags &= ~(PF_READ | PF_WREAD); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate if (!cv_wait_sig(&pty->pt_cv_writeq, &pty->ptc_lock)) { 505*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 506*0Sstevel@tonic-gate return (EINTR); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate out: 511*0Sstevel@tonic-gate if (pty->pt_flags & PF_WREAD) 512*0Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate pty->pt_flags &= ~(PF_READ | PF_WREAD); 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 517*0Sstevel@tonic-gate return (error); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate int 521*0Sstevel@tonic-gate ptcwrite(dev_t dev, struct uio *uio, struct cred *cred) 522*0Sstevel@tonic-gate { 523*0Sstevel@tonic-gate struct pty *pty = &pty_softc[getminor(dev)]; 524*0Sstevel@tonic-gate queue_t *q; 525*0Sstevel@tonic-gate int written; 526*0Sstevel@tonic-gate mblk_t *mp; 527*0Sstevel@tonic-gate int fmode = 0; 528*0Sstevel@tonic-gate int error = 0; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate off_t off; 531*0Sstevel@tonic-gate off = uio->uio_offset; 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate #ifdef lint 534*0Sstevel@tonic-gate cred = cred; 535*0Sstevel@tonic-gate #endif 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate again: 541*0Sstevel@tonic-gate while (pty->pt_flags & PF_WRITE) { 542*0Sstevel@tonic-gate pty->pt_flags |= PF_WWRITE; 543*0Sstevel@tonic-gate cv_wait(&pty->pt_cv_flags, &pty->ptc_lock); 544*0Sstevel@tonic-gate } 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate pty->pt_flags |= PF_WRITE; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) == NULL) { 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * Wait for slave to open. 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate if (pty->pt_flags & PF_SLAVEGONE) { 554*0Sstevel@tonic-gate error = EIO; 555*0Sstevel@tonic-gate goto out; 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate if (uio->uio_fmode & FNONBLOCK) { 558*0Sstevel@tonic-gate error = EAGAIN; 559*0Sstevel@tonic-gate goto out; 560*0Sstevel@tonic-gate } 561*0Sstevel@tonic-gate if (pty->pt_flags & PF_NBIO) { 562*0Sstevel@tonic-gate error = EWOULDBLOCK; 563*0Sstevel@tonic-gate goto out; 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate if (uio->uio_fmode & FNDELAY) 566*0Sstevel@tonic-gate goto out; 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate if (pty->pt_flags & PF_WWRITE) 569*0Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate pty->pt_flags &= ~(PF_WRITE | PF_WWRITE); 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate if (!cv_wait_sig(&pty->pt_cv_readq, &pty->ptc_lock)) { 574*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 575*0Sstevel@tonic-gate return (EINTR); 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate goto again; 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * If in remote mode, even zero-length writes generate messages. 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate written = 0; 585*0Sstevel@tonic-gate if ((pty->pt_flags & PF_REMOTE) || uio->uio_resid > 0) { 586*0Sstevel@tonic-gate do { 587*0Sstevel@tonic-gate while (!canput(q)) { 588*0Sstevel@tonic-gate /* 589*0Sstevel@tonic-gate * Wait for slave's read queue to unclog. 590*0Sstevel@tonic-gate */ 591*0Sstevel@tonic-gate if (pty->pt_flags & PF_SLAVEGONE) { 592*0Sstevel@tonic-gate error = EIO; 593*0Sstevel@tonic-gate goto out; 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate if (uio->uio_fmode & FNONBLOCK) { 596*0Sstevel@tonic-gate if (!written) 597*0Sstevel@tonic-gate error = EAGAIN; 598*0Sstevel@tonic-gate goto out; 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate if (pty->pt_flags & PF_NBIO) { 601*0Sstevel@tonic-gate if (!written) 602*0Sstevel@tonic-gate error = EWOULDBLOCK; 603*0Sstevel@tonic-gate goto out; 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate if (uio->uio_fmode & FNDELAY) 606*0Sstevel@tonic-gate goto out; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate if (pty->pt_flags & PF_WWRITE) 609*0Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate pty->pt_flags &= ~(PF_WRITE | PF_WWRITE); 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate if (!cv_wait_sig(&pty->pt_cv_readq, 614*0Sstevel@tonic-gate &pty->ptc_lock)) { 615*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 616*0Sstevel@tonic-gate return (EINTR); 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate while (pty->pt_flags & PF_WRITE) { 620*0Sstevel@tonic-gate pty->pt_flags |= PF_WWRITE; 621*0Sstevel@tonic-gate cv_wait(&pty->pt_cv_flags, 622*0Sstevel@tonic-gate &pty->ptc_lock); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate pty->pt_flags |= PF_WRITE; 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate if ((pty->pt_flags & PF_NBIO) && 629*0Sstevel@tonic-gate !(uio->uio_fmode & FNONBLOCK)) { 630*0Sstevel@tonic-gate fmode = uio->uio_fmode; 631*0Sstevel@tonic-gate uio->uio_fmode |= FNONBLOCK; 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate error = makemsg(uio->uio_resid, uio, pty, &mp); 635*0Sstevel@tonic-gate uio->uio_offset = off; 636*0Sstevel@tonic-gate if (fmode) 637*0Sstevel@tonic-gate uio->uio_fmode = fmode; 638*0Sstevel@tonic-gate if (error != 0) { 639*0Sstevel@tonic-gate if (error != EAGAIN && error != EWOULDBLOCK) 640*0Sstevel@tonic-gate goto out; 641*0Sstevel@tonic-gate if (uio->uio_fmode & FNONBLOCK) { 642*0Sstevel@tonic-gate if (!written) 643*0Sstevel@tonic-gate error = EAGAIN; 644*0Sstevel@tonic-gate goto out; 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate if (pty->pt_flags & PF_NBIO) { 647*0Sstevel@tonic-gate if (!written) 648*0Sstevel@tonic-gate error = EWOULDBLOCK; 649*0Sstevel@tonic-gate goto out; 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate if (uio->uio_fmode & FNDELAY) 652*0Sstevel@tonic-gate goto out; 653*0Sstevel@tonic-gate cmn_err(CE_PANIC, 654*0Sstevel@tonic-gate "ptcwrite: non null return from" 655*0Sstevel@tonic-gate " makemsg"); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * Check again for safety; since "uiomove" can take a 660*0Sstevel@tonic-gate * page fault, there's no guarantee that "pt_flags" 661*0Sstevel@tonic-gate * didn't change while it was happening. 662*0Sstevel@tonic-gate */ 663*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) == NULL) { 664*0Sstevel@tonic-gate if (mp) 665*0Sstevel@tonic-gate freemsg(mp); 666*0Sstevel@tonic-gate error = EIO; 667*0Sstevel@tonic-gate goto out; 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate if (mp) 670*0Sstevel@tonic-gate (void) putq(q, mp); 671*0Sstevel@tonic-gate written = 1; 672*0Sstevel@tonic-gate } while (uio->uio_resid > 0); 673*0Sstevel@tonic-gate } 674*0Sstevel@tonic-gate out: 675*0Sstevel@tonic-gate if (pty->pt_flags & PF_WWRITE) 676*0Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate pty->pt_flags &= ~(PF_WRITE | PF_WWRITE); 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 681*0Sstevel@tonic-gate return (error); 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate #define copy_in(data, d_arg) \ 685*0Sstevel@tonic-gate if (copyin((caddr_t)data, &d_arg, sizeof (int)) != 0) \ 686*0Sstevel@tonic-gate return (EFAULT) 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate #define copy_out(d_arg, data) \ 689*0Sstevel@tonic-gate if (copyout(&d_arg, (caddr_t)data, sizeof (int)) != 0) \ 690*0Sstevel@tonic-gate return (EFAULT) 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate int 693*0Sstevel@tonic-gate ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred, 694*0Sstevel@tonic-gate int *rvalp) 695*0Sstevel@tonic-gate { 696*0Sstevel@tonic-gate struct pty *pty = &pty_softc[getminor(dev)]; 697*0Sstevel@tonic-gate queue_t *q; 698*0Sstevel@tonic-gate struct ttysize tty_arg; 699*0Sstevel@tonic-gate struct winsize win_arg; 700*0Sstevel@tonic-gate int d_arg; 701*0Sstevel@tonic-gate int err; 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate switch (cmd) { 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate case TIOCPKT: 706*0Sstevel@tonic-gate copy_in(data, d_arg); 707*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 708*0Sstevel@tonic-gate if (d_arg) { 709*0Sstevel@tonic-gate if (pty->pt_flags & (PF_UCNTL|PF_43UCNTL)) { 710*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 711*0Sstevel@tonic-gate return (EINVAL); 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate pty->pt_flags |= PF_PKT; 714*0Sstevel@tonic-gate } else 715*0Sstevel@tonic-gate pty->pt_flags &= ~PF_PKT; 716*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 717*0Sstevel@tonic-gate break; 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate case TIOCUCNTL: 720*0Sstevel@tonic-gate copy_in(data, d_arg); 721*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 722*0Sstevel@tonic-gate if (d_arg) { 723*0Sstevel@tonic-gate if (pty->pt_flags & (PF_PKT|PF_UCNTL)) { 724*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 725*0Sstevel@tonic-gate return (EINVAL); 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate pty->pt_flags |= PF_43UCNTL; 728*0Sstevel@tonic-gate } else 729*0Sstevel@tonic-gate pty->pt_flags &= ~PF_43UCNTL; 730*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 731*0Sstevel@tonic-gate break; 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate case TIOCTCNTL: 734*0Sstevel@tonic-gate copy_in(data, d_arg); 735*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 736*0Sstevel@tonic-gate if (d_arg) { 737*0Sstevel@tonic-gate if (pty->pt_flags & PF_PKT) { 738*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 739*0Sstevel@tonic-gate return (EINVAL); 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate pty->pt_flags |= PF_UCNTL; 742*0Sstevel@tonic-gate } else 743*0Sstevel@tonic-gate pty->pt_flags &= ~PF_UCNTL; 744*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 745*0Sstevel@tonic-gate break; 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate case TIOCREMOTE: 748*0Sstevel@tonic-gate copy_in(data, d_arg); 749*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 750*0Sstevel@tonic-gate if (d_arg) { 751*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL) 752*0Sstevel@tonic-gate (void) putctl1(q, M_CTL, MC_NOCANON); 753*0Sstevel@tonic-gate pty->pt_flags |= PF_REMOTE; 754*0Sstevel@tonic-gate } else { 755*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL) 756*0Sstevel@tonic-gate (void) putctl1(q, M_CTL, MC_DOCANON); 757*0Sstevel@tonic-gate pty->pt_flags &= ~PF_REMOTE; 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 760*0Sstevel@tonic-gate break; 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate case TIOCSIGNAL: 763*0Sstevel@tonic-gate /* 764*0Sstevel@tonic-gate * Blast a M_PCSIG message up the slave stream; the 765*0Sstevel@tonic-gate * signal number is the argument to the "ioctl". 766*0Sstevel@tonic-gate */ 767*0Sstevel@tonic-gate copy_in(data, d_arg); 768*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 769*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL) 770*0Sstevel@tonic-gate (void) putctl1(q, M_PCSIG, (int)d_arg); 771*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 772*0Sstevel@tonic-gate break; 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate case FIONBIO: 775*0Sstevel@tonic-gate copy_in(data, d_arg); 776*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 777*0Sstevel@tonic-gate if (d_arg) 778*0Sstevel@tonic-gate pty->pt_flags |= PF_NBIO; 779*0Sstevel@tonic-gate else 780*0Sstevel@tonic-gate pty->pt_flags &= ~PF_NBIO; 781*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 782*0Sstevel@tonic-gate break; 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate case FIOASYNC: 785*0Sstevel@tonic-gate copy_in(data, d_arg); 786*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 787*0Sstevel@tonic-gate if (d_arg) 788*0Sstevel@tonic-gate pty->pt_flags |= PF_ASYNC; 789*0Sstevel@tonic-gate else 790*0Sstevel@tonic-gate pty->pt_flags &= ~PF_ASYNC; 791*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 792*0Sstevel@tonic-gate break; 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate /* 795*0Sstevel@tonic-gate * These, at least, can work on the controller-side process 796*0Sstevel@tonic-gate * group. 797*0Sstevel@tonic-gate */ 798*0Sstevel@tonic-gate case FIOGETOWN: 799*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 800*0Sstevel@tonic-gate d_arg = -pty->pt_pgrp; 801*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 802*0Sstevel@tonic-gate copy_out(d_arg, data); 803*0Sstevel@tonic-gate break; 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate case FIOSETOWN: 806*0Sstevel@tonic-gate copy_in(data, d_arg); 807*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 808*0Sstevel@tonic-gate pty->pt_pgrp = (short)(-d_arg); 809*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 810*0Sstevel@tonic-gate break; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate case FIONREAD: { 813*0Sstevel@tonic-gate /* 814*0Sstevel@tonic-gate * Return the total number of bytes of data in all messages 815*0Sstevel@tonic-gate * in slave write queue, which is master read queue, unless a 816*0Sstevel@tonic-gate * special message would be read. 817*0Sstevel@tonic-gate */ 818*0Sstevel@tonic-gate mblk_t *mp; 819*0Sstevel@tonic-gate size_t count = 0; 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 822*0Sstevel@tonic-gate if (pty->pt_flags&(PF_PKT|PF_UCNTL) && pty->pt_send) 823*0Sstevel@tonic-gate count = 1; /* will return 1 byte */ 824*0Sstevel@tonic-gate else if ((pty->pt_flags & (PF_UCNTL|PF_43UCNTL)) && 825*0Sstevel@tonic-gate pty->pt_ucntl) 826*0Sstevel@tonic-gate count = 1; /* will return 1 byte */ 827*0Sstevel@tonic-gate else if ((q = pty->pt_ttycommon.t_writeq) != NULL && 828*0Sstevel@tonic-gate q->q_first != NULL && !(pty->pt_flags & PF_STOPPED)) { 829*0Sstevel@tonic-gate /* 830*0Sstevel@tonic-gate * Will return whatever data is queued up. 831*0Sstevel@tonic-gate */ 832*0Sstevel@tonic-gate for (mp = q->q_first; mp != NULL; mp = mp->b_next) 833*0Sstevel@tonic-gate count += msgdsize(mp); 834*0Sstevel@tonic-gate } else if ((pty->pt_flags & PF_UCNTL) && 835*0Sstevel@tonic-gate pty->pt_stuffqfirst != NULL) { 836*0Sstevel@tonic-gate /* 837*0Sstevel@tonic-gate * Will return STI'ed data. 838*0Sstevel@tonic-gate */ 839*0Sstevel@tonic-gate count = pty->pt_stuffqlen + 1; 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate /* 843*0Sstevel@tonic-gate * Under LP64 we could have more than INT_MAX bytes to report, 844*0Sstevel@tonic-gate * but the interface is defined in terms of int, so we cap it. 845*0Sstevel@tonic-gate */ 846*0Sstevel@tonic-gate d_arg = MIN(count, INT_MAX); 847*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 848*0Sstevel@tonic-gate copy_out(d_arg, data); 849*0Sstevel@tonic-gate break; 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate case TIOCSWINSZ: 853*0Sstevel@tonic-gate /* 854*0Sstevel@tonic-gate * Unfortunately, TIOCSWINSZ and the old TIOCSSIZE "ioctl"s 855*0Sstevel@tonic-gate * share the same code. If the upper 16 bits of the number 856*0Sstevel@tonic-gate * of lines is non-zero, it was probably a TIOCSWINSZ, 857*0Sstevel@tonic-gate * with both "ws_row" and "ws_col" non-zero. 858*0Sstevel@tonic-gate */ 859*0Sstevel@tonic-gate if (copyin((caddr_t)data, 860*0Sstevel@tonic-gate &tty_arg, sizeof (struct ttysize)) != 0) 861*0Sstevel@tonic-gate return (EFAULT); 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate if ((tty_arg.ts_lines & 0xffff0000) != 0) { 864*0Sstevel@tonic-gate /* 865*0Sstevel@tonic-gate * It's a TIOCSWINSZ. 866*0Sstevel@tonic-gate */ 867*0Sstevel@tonic-gate win_arg = *(struct winsize *)&tty_arg; 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 870*0Sstevel@tonic-gate /* 871*0Sstevel@tonic-gate * If the window size changed, send a SIGWINCH. 872*0Sstevel@tonic-gate */ 873*0Sstevel@tonic-gate if (bcmp(&pty->pt_ttycommon.t_size, 874*0Sstevel@tonic-gate &win_arg, sizeof (struct winsize))) { 875*0Sstevel@tonic-gate pty->pt_ttycommon.t_size = win_arg; 876*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL) 877*0Sstevel@tonic-gate (void) putctl1(q, M_PCSIG, SIGWINCH); 878*0Sstevel@tonic-gate } 879*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 880*0Sstevel@tonic-gate break; 881*0Sstevel@tonic-gate } 882*0Sstevel@tonic-gate /* FALLTHROUGH */ 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate case TIOCSSIZE: 885*0Sstevel@tonic-gate if (copyin((caddr_t)data, 886*0Sstevel@tonic-gate &tty_arg, sizeof (struct ttysize)) != 0) 887*0Sstevel@tonic-gate return (EFAULT); 888*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 889*0Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_row = (ushort_t)tty_arg.ts_lines; 890*0Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_col = (ushort_t)tty_arg.ts_cols; 891*0Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_xpixel = 0; 892*0Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_ypixel = 0; 893*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 894*0Sstevel@tonic-gate break; 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate case TIOCGWINSZ: 897*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 898*0Sstevel@tonic-gate win_arg = pty->pt_ttycommon.t_size; 899*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 900*0Sstevel@tonic-gate if (copyout(&win_arg, (caddr_t)data, 901*0Sstevel@tonic-gate sizeof (struct winsize)) != 0) 902*0Sstevel@tonic-gate return (EFAULT); 903*0Sstevel@tonic-gate break; 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate case TIOCGSIZE: 906*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 907*0Sstevel@tonic-gate tty_arg.ts_lines = pty->pt_ttycommon.t_size.ws_row; 908*0Sstevel@tonic-gate tty_arg.ts_cols = pty->pt_ttycommon.t_size.ws_col; 909*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 910*0Sstevel@tonic-gate if (copyout(&tty_arg, (caddr_t)data, 911*0Sstevel@tonic-gate sizeof (struct ttysize)) != 0) 912*0Sstevel@tonic-gate return (EFAULT); 913*0Sstevel@tonic-gate break; 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate /* 916*0Sstevel@tonic-gate * XXX These should not be here. The only reason why an 917*0Sstevel@tonic-gate * "ioctl" on the controller side should get the 918*0Sstevel@tonic-gate * slave side's process group is so that the process on 919*0Sstevel@tonic-gate * the controller side can send a signal to the slave 920*0Sstevel@tonic-gate * side's process group; however, this is better done 921*0Sstevel@tonic-gate * with TIOCSIGNAL, both because it doesn't require us 922*0Sstevel@tonic-gate * to know about the slave side's process group and because 923*0Sstevel@tonic-gate * the controller side process may not have permission to 924*0Sstevel@tonic-gate * send that signal to the entire process group. 925*0Sstevel@tonic-gate * 926*0Sstevel@tonic-gate * However, since vanilla 4BSD doesn't provide TIOCSIGNAL, 927*0Sstevel@tonic-gate * we can't just get rid of them. 928*0Sstevel@tonic-gate */ 929*0Sstevel@tonic-gate case TIOCGPGRP: 930*0Sstevel@tonic-gate case TIOCSPGRP: 931*0Sstevel@tonic-gate /* 932*0Sstevel@tonic-gate * This is amazingly disgusting, but the stupid semantics of 933*0Sstevel@tonic-gate * 4BSD pseudo-ttys makes us do it. If we do one of these guys 934*0Sstevel@tonic-gate * on the controller side, it really applies to the slave-side 935*0Sstevel@tonic-gate * stream. It should NEVER have been possible to do ANY sort 936*0Sstevel@tonic-gate * of tty operations on the controller side, but it's too late 937*0Sstevel@tonic-gate * to fix that now. However, we won't waste our time implementing 938*0Sstevel@tonic-gate * anything that the original pseudo-tty driver didn't handle. 939*0Sstevel@tonic-gate */ 940*0Sstevel@tonic-gate case TIOCGETP: 941*0Sstevel@tonic-gate case TIOCSETP: 942*0Sstevel@tonic-gate case TIOCSETN: 943*0Sstevel@tonic-gate case TIOCGETC: 944*0Sstevel@tonic-gate case TIOCSETC: 945*0Sstevel@tonic-gate case TIOCGLTC: 946*0Sstevel@tonic-gate case TIOCSLTC: 947*0Sstevel@tonic-gate case TIOCLGET: 948*0Sstevel@tonic-gate case TIOCLSET: 949*0Sstevel@tonic-gate case TIOCLBIS: 950*0Sstevel@tonic-gate case TIOCLBIC: 951*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 952*0Sstevel@tonic-gate if (pty->pt_vnode == NULL) { 953*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 954*0Sstevel@tonic-gate return (EIO); 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate pty->pt_flags |= PF_IOCTL; 957*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 958*0Sstevel@tonic-gate err = strioctl(pty->pt_vnode, cmd, data, flag, 959*0Sstevel@tonic-gate U_TO_K, cred, rvalp); 960*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 961*0Sstevel@tonic-gate if (pty->pt_flags & PF_WAIT) 962*0Sstevel@tonic-gate cv_signal(&pty->pt_cv_flags); 963*0Sstevel@tonic-gate pty->pt_flags &= ~(PF_IOCTL|PF_WAIT); 964*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 965*0Sstevel@tonic-gate return (err); 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate default: 968*0Sstevel@tonic-gate return (ENOTTY); 969*0Sstevel@tonic-gate } 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate return (0); 972*0Sstevel@tonic-gate } 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate 975*0Sstevel@tonic-gate int 976*0Sstevel@tonic-gate ptcpoll(dev_t dev, 977*0Sstevel@tonic-gate short events, 978*0Sstevel@tonic-gate int anyyet, 979*0Sstevel@tonic-gate short *reventsp, 980*0Sstevel@tonic-gate struct pollhead **phpp) 981*0Sstevel@tonic-gate { 982*0Sstevel@tonic-gate struct pty *pty = &pty_softc[getminor(dev)]; 983*0Sstevel@tonic-gate pollhead_t *php = &ptcph; 984*0Sstevel@tonic-gate queue_t *q; 985*0Sstevel@tonic-gate int pos = 0; 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate #ifdef lint 988*0Sstevel@tonic-gate anyyet = anyyet; 989*0Sstevel@tonic-gate #endif 990*0Sstevel@tonic-gate polllock(php, &pty->ptc_lock); 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate *reventsp = 0; 995*0Sstevel@tonic-gate if (pty->pt_flags & PF_SLAVEGONE) { 996*0Sstevel@tonic-gate if (events & (POLLIN|POLLRDNORM)) 997*0Sstevel@tonic-gate *reventsp |= (events & (POLLIN|POLLRDNORM)); 998*0Sstevel@tonic-gate if (events & (POLLOUT|POLLWRNORM)) 999*0Sstevel@tonic-gate *reventsp |= (events & (POLLOUT|POLLWRNORM)); 1000*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 1001*0Sstevel@tonic-gate /* 1002*0Sstevel@tonic-gate * A non NULL pollhead pointer should be returned in case 1003*0Sstevel@tonic-gate * user polls for 0 events. 1004*0Sstevel@tonic-gate */ 1005*0Sstevel@tonic-gate *phpp = !anyyet && !*reventsp ? php : (struct pollhead *)NULL; 1006*0Sstevel@tonic-gate return (0); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate if (events & (POLLIN|POLLRDNORM)) { 1009*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_writeq) != NULL && 1010*0Sstevel@tonic-gate q->q_first != NULL && !(pty->pt_flags & PF_STOPPED)) { 1011*0Sstevel@tonic-gate /* 1012*0Sstevel@tonic-gate * Regular data is available. 1013*0Sstevel@tonic-gate */ 1014*0Sstevel@tonic-gate *reventsp |= (events & (POLLIN|POLLRDNORM)); 1015*0Sstevel@tonic-gate pos++; 1016*0Sstevel@tonic-gate } 1017*0Sstevel@tonic-gate if (pty->pt_flags & (PF_PKT|PF_UCNTL) && pty->pt_send) { 1018*0Sstevel@tonic-gate /* 1019*0Sstevel@tonic-gate * A control packet is available. 1020*0Sstevel@tonic-gate */ 1021*0Sstevel@tonic-gate *reventsp |= (events & (POLLIN|POLLRDNORM)); 1022*0Sstevel@tonic-gate pos++; 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate if ((pty->pt_flags & PF_UCNTL) && 1025*0Sstevel@tonic-gate (pty->pt_ucntl || pty->pt_stuffqfirst != NULL)) { 1026*0Sstevel@tonic-gate /* 1027*0Sstevel@tonic-gate * "ioctl" or TIOCSTI data is available. 1028*0Sstevel@tonic-gate */ 1029*0Sstevel@tonic-gate *reventsp |= (events & (POLLIN|POLLRDNORM)); 1030*0Sstevel@tonic-gate pos++; 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate if ((pty->pt_flags & PF_43UCNTL) && pty->pt_ucntl) { 1033*0Sstevel@tonic-gate *reventsp |= (events & (POLLIN|POLLRDNORM)); 1034*0Sstevel@tonic-gate pos++; 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate } 1037*0Sstevel@tonic-gate if (events & (POLLOUT|POLLWRNORM)) { 1038*0Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_readq) != NULL && 1039*0Sstevel@tonic-gate canput(q)) { 1040*0Sstevel@tonic-gate *reventsp |= (events & (POLLOUT|POLLWRNORM)); 1041*0Sstevel@tonic-gate pos++; 1042*0Sstevel@tonic-gate } 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate if (events & POLLERR) { 1045*0Sstevel@tonic-gate *reventsp |= POLLERR; 1046*0Sstevel@tonic-gate pos++; 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate if (events == 0) { /* "exceptional conditions" */ 1049*0Sstevel@tonic-gate if (((pty->pt_flags & (PF_PKT|PF_UCNTL)) && pty->pt_send) || 1050*0Sstevel@tonic-gate ((pty->pt_flags & PF_UCNTL) && 1051*0Sstevel@tonic-gate (pty->pt_ucntl || pty->pt_stuffqfirst != NULL))) { 1052*0Sstevel@tonic-gate pos++; 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate if ((pty->pt_flags & PF_43UCNTL) && pty->pt_ucntl) { 1055*0Sstevel@tonic-gate pos++; 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate } 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate /* 1060*0Sstevel@tonic-gate * Arrange to have poll waken up when event occurs. 1061*0Sstevel@tonic-gate * if (!anyyet) 1062*0Sstevel@tonic-gate */ 1063*0Sstevel@tonic-gate if (!pos) { 1064*0Sstevel@tonic-gate *phpp = php; 1065*0Sstevel@tonic-gate *reventsp = 0; 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 1069*0Sstevel@tonic-gate return (0); 1070*0Sstevel@tonic-gate } 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate void 1073*0Sstevel@tonic-gate gsignal(int pid, int sig) 1074*0Sstevel@tonic-gate { 1075*0Sstevel@tonic-gate procset_t set; 1076*0Sstevel@tonic-gate sigsend_t v; 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate bzero(&v, sizeof (v)); 1079*0Sstevel@tonic-gate v.sig = sig; 1080*0Sstevel@tonic-gate v.perm = 0; 1081*0Sstevel@tonic-gate v.checkperm = 1; 1082*0Sstevel@tonic-gate v.value.sival_ptr = NULL; 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate setprocset(&set, POP_AND, P_PGID, -pid, P_ALL, P_MYID); 1085*0Sstevel@tonic-gate (void) sigsendset(&set, &v); 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate static int 1089*0Sstevel@tonic-gate makemsg(ssize_t count, struct uio *uiop, struct pty *pty, mblk_t **mpp) 1090*0Sstevel@tonic-gate { 1091*0Sstevel@tonic-gate int pri = BPRI_LO; 1092*0Sstevel@tonic-gate int error; 1093*0Sstevel@tonic-gate mblk_t *bp = NULL; 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate *mpp = NULL; 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* 1100*0Sstevel@tonic-gate * Create data part of message, if any. 1101*0Sstevel@tonic-gate */ 1102*0Sstevel@tonic-gate if (count >= 0) { 1103*0Sstevel@tonic-gate if ((bp = allocb(count, pri)) == NULL) 1104*0Sstevel@tonic-gate return (ENOSR); 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 1107*0Sstevel@tonic-gate error = uiomove((caddr_t)bp->b_wptr, count, UIO_WRITE, uiop); 1108*0Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 1109*0Sstevel@tonic-gate if (error) { 1110*0Sstevel@tonic-gate freeb(bp); 1111*0Sstevel@tonic-gate return (error); 1112*0Sstevel@tonic-gate } 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate bp->b_wptr += count; 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate *mpp = bp; 1118*0Sstevel@tonic-gate return (0); 1119*0Sstevel@tonic-gate } 1120