10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52712Snn35248 * Common Development and Distribution License (the "License"). 62712Snn35248 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5331Samw * Copyright 2007 Sun Microsystems, Inc. 230Sstevel@tonic-gate * All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate /* from S5R4 1.22 */ 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 350Sstevel@tonic-gate * Indirect driver for controlling tty. 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate #include <sys/types.h> 380Sstevel@tonic-gate #include <sys/errno.h> 390Sstevel@tonic-gate #include <sys/conf.h> 400Sstevel@tonic-gate #include <sys/proc.h> 410Sstevel@tonic-gate #include <sys/tty.h> 420Sstevel@tonic-gate #include <sys/stream.h> 430Sstevel@tonic-gate #include <sys/strsubr.h> 440Sstevel@tonic-gate #include <sys/cred.h> 450Sstevel@tonic-gate #include <sys/uio.h> 460Sstevel@tonic-gate #include <sys/session.h> 470Sstevel@tonic-gate #include <sys/ddi.h> 480Sstevel@tonic-gate #include <sys/debug.h> 490Sstevel@tonic-gate #include <sys/stat.h> 500Sstevel@tonic-gate #include <sys/sunddi.h> 510Sstevel@tonic-gate #include <sys/param.h> 520Sstevel@tonic-gate #include <sys/systm.h> 530Sstevel@tonic-gate #include <sys/modctl.h> 540Sstevel@tonic-gate #include <sys/fs/snode.h> 550Sstevel@tonic-gate #include <sys/file.h> 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define IS_STREAM(dev) (devopsp[getmajor(dev)]->devo_cb_ops->cb_str != NULL) 580Sstevel@tonic-gate 590Sstevel@tonic-gate int syopen(dev_t *, int, int, cred_t *); 600Sstevel@tonic-gate int syclose(dev_t, int, int, cred_t *); 610Sstevel@tonic-gate int syread(dev_t, struct uio *, cred_t *); 620Sstevel@tonic-gate int sywrite(dev_t, struct uio *, cred_t *); 630Sstevel@tonic-gate int sypoll(dev_t, short, int, short *, struct pollhead **); 640Sstevel@tonic-gate int syioctl(dev_t, int, intptr_t, int, cred_t *, int *); 650Sstevel@tonic-gate 660Sstevel@tonic-gate static int sy_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 670Sstevel@tonic-gate static int sy_attach(dev_info_t *, ddi_attach_cmd_t); 680Sstevel@tonic-gate static dev_info_t *sy_dip; /* private copy of devinfo pointer */ 690Sstevel@tonic-gate 700Sstevel@tonic-gate struct cb_ops sy_cb_ops = { 710Sstevel@tonic-gate 720Sstevel@tonic-gate syopen, /* open */ 730Sstevel@tonic-gate syclose, /* close */ 740Sstevel@tonic-gate nodev, /* strategy */ 750Sstevel@tonic-gate nodev, /* print */ 760Sstevel@tonic-gate nodev, /* dump */ 770Sstevel@tonic-gate syread, /* read */ 780Sstevel@tonic-gate sywrite, /* write */ 790Sstevel@tonic-gate syioctl, /* ioctl */ 800Sstevel@tonic-gate nodev, /* devmap */ 810Sstevel@tonic-gate nodev, /* mmap */ 820Sstevel@tonic-gate nodev, /* segmap */ 830Sstevel@tonic-gate sypoll, /* poll */ 840Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 850Sstevel@tonic-gate 0, /* streamtab */ 860Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 870Sstevel@tonic-gate 880Sstevel@tonic-gate }; 890Sstevel@tonic-gate 900Sstevel@tonic-gate struct dev_ops sy_ops = { 910Sstevel@tonic-gate 920Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 930Sstevel@tonic-gate 0, /* refcnt */ 940Sstevel@tonic-gate sy_info, /* info */ 950Sstevel@tonic-gate nulldev, /* identify */ 960Sstevel@tonic-gate nulldev, /* probe */ 970Sstevel@tonic-gate sy_attach, /* attach */ 980Sstevel@tonic-gate nodev, /* detach */ 990Sstevel@tonic-gate nodev, /* reset */ 1000Sstevel@tonic-gate &sy_cb_ops, /* driver operations */ 1010Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations */ 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate }; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate extern int nodev(void); 1070Sstevel@tonic-gate extern int nulldev(void); 1080Sstevel@tonic-gate extern int dseekneg_flag; 1090Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1100Sstevel@tonic-gate extern struct dev_ops sy_ops; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * Module linkage information for the kernel. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate static struct modldrv modldrv = { 1170Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 1180Sstevel@tonic-gate "Indirect driver for tty 'sy' %I%", 1190Sstevel@tonic-gate &sy_ops, /* driver ops */ 1200Sstevel@tonic-gate }; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static struct modlinkage modlinkage = { 1230Sstevel@tonic-gate MODREV_1, 1240Sstevel@tonic-gate &modldrv, 1250Sstevel@tonic-gate NULL 1260Sstevel@tonic-gate }; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate int 1300Sstevel@tonic-gate _init(void) 1310Sstevel@tonic-gate { 1320Sstevel@tonic-gate return (mod_install(&modlinkage)); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate int 1370Sstevel@tonic-gate _fini(void) 1380Sstevel@tonic-gate { 1390Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate int 1430Sstevel@tonic-gate _info(struct modinfo *modinfop) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* ARGSUSED */ 1490Sstevel@tonic-gate static int 1500Sstevel@tonic-gate sy_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1510Sstevel@tonic-gate { 1520Sstevel@tonic-gate if (ddi_create_minor_node(devi, "tty", S_IFCHR, 1530Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1540Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1550Sstevel@tonic-gate return (-1); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate sy_dip = devi; 1580Sstevel@tonic-gate return (DDI_SUCCESS); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* ARGSUSED */ 1620Sstevel@tonic-gate static int 1630Sstevel@tonic-gate sy_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1640Sstevel@tonic-gate { 1650Sstevel@tonic-gate dev_t dev = (dev_t)arg; 1660Sstevel@tonic-gate int error; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate switch (infocmd) { 1690Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1700Sstevel@tonic-gate if (sy_dip == NULL) { 1710Sstevel@tonic-gate *result = (void *)NULL; 1720Sstevel@tonic-gate error = DDI_FAILURE; 1730Sstevel@tonic-gate } else { 1740Sstevel@tonic-gate *result = (void *) sy_dip; 1750Sstevel@tonic-gate error = DDI_SUCCESS; 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1790Sstevel@tonic-gate if (getminor(dev) != 0) { 1800Sstevel@tonic-gate *result = (void *)-1; 1810Sstevel@tonic-gate error = DDI_FAILURE; 1820Sstevel@tonic-gate } else { 1830Sstevel@tonic-gate *result = (void *)0; 1840Sstevel@tonic-gate error = DDI_SUCCESS; 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate default: 1880Sstevel@tonic-gate error = DDI_FAILURE; 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate return (error); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* ARGSUSED */ 1950Sstevel@tonic-gate int 1960Sstevel@tonic-gate syopen(dev_t *devp, int flag, int otyp, struct cred *cr) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate dev_t ttyd; 1990Sstevel@tonic-gate vnode_t *ttyvp; 2002712Snn35248 sess_t *sp; 2010Sstevel@tonic-gate int error; 2020Sstevel@tonic-gate 2032712Snn35248 if ((sp = tty_hold()) == NULL) 2042712Snn35248 return (EINTR); 2052712Snn35248 2062712Snn35248 if (sp->s_dev == NODEV) { 2072712Snn35248 tty_rele(sp); 2080Sstevel@tonic-gate return (ENXIO); 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate 2112712Snn35248 ttyd = sp->s_dev; 2122712Snn35248 ttyvp = sp->s_vp; 2132712Snn35248 2140Sstevel@tonic-gate /* 2150Sstevel@tonic-gate * Open the control terminal. The control terminal may be 2160Sstevel@tonic-gate * opened multiple times and it is closed in freectty(). 2170Sstevel@tonic-gate * The multi-open, single-clone means that no cloning 2180Sstevel@tonic-gate * can happen via this open, hence the assertion. 2190Sstevel@tonic-gate */ 220*5331Samw error = VOP_OPEN(&ttyvp, FNOCTTY | flag, cr, NULL); 2210Sstevel@tonic-gate if (error == 0) { 2220Sstevel@tonic-gate struct snode *csp; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * XXX: This driver binds a single minor number to the 2260Sstevel@tonic-gate * current controlling tty of the process issueing the 2270Sstevel@tonic-gate * open / close. If we implement a traditional close 2280Sstevel@tonic-gate * for this driver then specfs will only invoke this driver 2290Sstevel@tonic-gate * on the last close of our one minor number - which is not 2300Sstevel@tonic-gate * what we want. Since we already get the open / close 2310Sstevel@tonic-gate * semantic that we want from makectty and freectty, we reach 2320Sstevel@tonic-gate * back into the common snode and decrease the open count so 2330Sstevel@tonic-gate * that the specfs filtering of all but the last close 2340Sstevel@tonic-gate * does not get in our way. To clean this up, a new cb_flag 2350Sstevel@tonic-gate * that causes specfs to call the driver on each close 2360Sstevel@tonic-gate * should be considered. 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate ASSERT(ttyd == ttyvp->v_rdev); 2390Sstevel@tonic-gate ASSERT(vn_matchops(ttyvp, spec_getvnodeops())); 2400Sstevel@tonic-gate csp = VTOS(VTOS(ttyvp)->s_commonvp); 2410Sstevel@tonic-gate mutex_enter(&csp->s_lock); 2422712Snn35248 ASSERT(csp->s_count > 1); 2430Sstevel@tonic-gate csp->s_count--; 2440Sstevel@tonic-gate mutex_exit(&csp->s_lock); 2450Sstevel@tonic-gate } 2462712Snn35248 2472712Snn35248 tty_rele(sp); 2480Sstevel@tonic-gate return (error); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* ARGSUSED */ 2520Sstevel@tonic-gate int 2530Sstevel@tonic-gate syclose(dev_t dev, int flag, int otyp, struct cred *cr) 2540Sstevel@tonic-gate { 2550Sstevel@tonic-gate return (0); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate /* ARGSUSED */ 2590Sstevel@tonic-gate int 2600Sstevel@tonic-gate syread(dev_t dev, struct uio *uiop, struct cred *cr) 2610Sstevel@tonic-gate { 2622712Snn35248 sess_t *sp; 2630Sstevel@tonic-gate int error; 2640Sstevel@tonic-gate 2652712Snn35248 if ((sp = tty_hold()) == NULL) 2662712Snn35248 return (EINTR); 2672712Snn35248 2682712Snn35248 if (sp->s_dev == NODEV) { 2692712Snn35248 tty_rele(sp); 2700Sstevel@tonic-gate return (ENXIO); 2710Sstevel@tonic-gate } 2722712Snn35248 2732712Snn35248 error = VOP_READ(sp->s_vp, uiop, 0, cr, NULL); 2742712Snn35248 2752712Snn35248 tty_rele(sp); 2760Sstevel@tonic-gate return (error); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* ARGSUSED */ 2800Sstevel@tonic-gate int 2810Sstevel@tonic-gate sywrite(dev_t dev, struct uio *uiop, struct cred *cr) 2820Sstevel@tonic-gate { 2832712Snn35248 sess_t *sp; 2840Sstevel@tonic-gate int error; 2850Sstevel@tonic-gate 2862712Snn35248 if ((sp = tty_hold()) == NULL) 2872712Snn35248 return (EINTR); 2882712Snn35248 2892712Snn35248 if (sp->s_dev == NODEV) { 2902712Snn35248 tty_rele(sp); 2910Sstevel@tonic-gate return (ENXIO); 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2942712Snn35248 error = VOP_WRITE(sp->s_vp, uiop, 0, cr, NULL); 2952712Snn35248 2962712Snn35248 tty_rele(sp); 2970Sstevel@tonic-gate return (error); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /* ARGSUSED */ 3020Sstevel@tonic-gate int 3030Sstevel@tonic-gate syioctl(dev_t dev, int cmd, intptr_t arg, int mode, struct cred *cr, 3040Sstevel@tonic-gate int *rvalp) 3050Sstevel@tonic-gate { 3062712Snn35248 sess_t *sp; 3070Sstevel@tonic-gate int error; 3080Sstevel@tonic-gate 3092712Snn35248 if (cmd == TIOCNOTTY) { 3102712Snn35248 /* 3112712Snn35248 * we can't allow this ioctl. the reason is that it 3122712Snn35248 * attempts to remove the ctty for a session. to do 3132712Snn35248 * this the ctty can't be in use but we grab a hold on 3142712Snn35248 * the current ctty (via tty_hold) to perform this ioctl. 3152712Snn35248 * if we were to allow this ioctl to pass through we 3162712Snn35248 * would deadlock with ourselves. 3172712Snn35248 */ 3182712Snn35248 return (EINVAL); 3192712Snn35248 } 3202712Snn35248 3212712Snn35248 if ((sp = tty_hold()) == NULL) 3222712Snn35248 return (EINTR); 3232712Snn35248 3242712Snn35248 if (sp->s_dev == NODEV) { 3252712Snn35248 tty_rele(sp); 3260Sstevel@tonic-gate return (ENXIO); 3270Sstevel@tonic-gate } 3282712Snn35248 329*5331Samw error = VOP_IOCTL(sp->s_vp, cmd, arg, mode, cr, rvalp, NULL); 3302712Snn35248 3312712Snn35248 tty_rele(sp); 3320Sstevel@tonic-gate return (error); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate /* ARGSUSED */ 3380Sstevel@tonic-gate int 3390Sstevel@tonic-gate sypoll(dev_t dev, short events, int anyyet, short *reventsp, 3400Sstevel@tonic-gate struct pollhead **phpp) 3410Sstevel@tonic-gate { 3422712Snn35248 sess_t *sp; 3430Sstevel@tonic-gate int error; 3440Sstevel@tonic-gate 3452712Snn35248 if ((sp = tty_hold()) == NULL) 3462712Snn35248 return (EINTR); 3472712Snn35248 3482712Snn35248 if (sp->s_dev == NODEV) { 3492712Snn35248 tty_rele(sp); 3500Sstevel@tonic-gate return (ENXIO); 3510Sstevel@tonic-gate } 3522712Snn35248 353*5331Samw error = VOP_POLL(sp->s_vp, events, anyyet, reventsp, phpp, NULL); 3542712Snn35248 3552712Snn35248 tty_rele(sp); 3560Sstevel@tonic-gate return (error); 3570Sstevel@tonic-gate } 358