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
55331Samw * Common Development and Distribution License (the "License").
65331Samw * 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*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * System message redirection driver for Sun.
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * Redirects system message output to the device designated as the underlying
310Sstevel@tonic-gate * "hardware" console, as given by the value of sysmvp. The implementation
320Sstevel@tonic-gate * assumes that sysmvp denotes a STREAMS device; the assumption is justified
330Sstevel@tonic-gate * since consoles must be capable of effecting tty semantics.
340Sstevel@tonic-gate */
350Sstevel@tonic-gate
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/kmem.h>
380Sstevel@tonic-gate #include <sys/open.h>
390Sstevel@tonic-gate #include <sys/param.h>
400Sstevel@tonic-gate #include <sys/systm.h>
410Sstevel@tonic-gate #include <sys/signal.h>
420Sstevel@tonic-gate #include <sys/cred.h>
430Sstevel@tonic-gate #include <sys/user.h>
440Sstevel@tonic-gate #include <sys/proc.h>
450Sstevel@tonic-gate #include <sys/vnode.h>
460Sstevel@tonic-gate #include <sys/uio.h>
470Sstevel@tonic-gate #include <sys/stat.h>
480Sstevel@tonic-gate #include <sys/file.h>
49560Smeem #include <sys/session.h>
500Sstevel@tonic-gate #include <sys/stream.h>
510Sstevel@tonic-gate #include <sys/strsubr.h>
520Sstevel@tonic-gate #include <sys/poll.h>
530Sstevel@tonic-gate #include <sys/debug.h>
540Sstevel@tonic-gate #include <sys/sysmsg_impl.h>
550Sstevel@tonic-gate #include <sys/conf.h>
560Sstevel@tonic-gate #include <sys/termios.h>
570Sstevel@tonic-gate #include <sys/errno.h>
580Sstevel@tonic-gate #include <sys/modctl.h>
590Sstevel@tonic-gate #include <sys/pathname.h>
600Sstevel@tonic-gate #include <sys/ddi.h>
610Sstevel@tonic-gate #include <sys/sunddi.h>
620Sstevel@tonic-gate #include <sys/consdev.h>
630Sstevel@tonic-gate #include <sys/policy.h>
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * internal functions
670Sstevel@tonic-gate */
680Sstevel@tonic-gate static int sysmopen(dev_t *, int, int, cred_t *);
690Sstevel@tonic-gate static int sysmclose(dev_t, int, int, cred_t *);
700Sstevel@tonic-gate static int sysmread(dev_t, struct uio *, cred_t *);
710Sstevel@tonic-gate static int sysmwrite(dev_t, struct uio *, cred_t *);
720Sstevel@tonic-gate static int sysmioctl(dev_t, int, intptr_t, int, cred_t *, int *);
730Sstevel@tonic-gate static int sysmpoll(dev_t, short, int, short *, struct pollhead **);
740Sstevel@tonic-gate static int sysm_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
750Sstevel@tonic-gate static int sysm_attach(dev_info_t *, ddi_attach_cmd_t);
760Sstevel@tonic-gate static int sysm_detach(dev_info_t *, ddi_detach_cmd_t);
770Sstevel@tonic-gate static void bind_consadm_conf(char *);
780Sstevel@tonic-gate static int checkarg(dev_t);
790Sstevel@tonic-gate
800Sstevel@tonic-gate static dev_info_t *sysm_dip; /* private copy of devinfo pointer */
810Sstevel@tonic-gate
820Sstevel@tonic-gate static struct cb_ops sysm_cb_ops = {
830Sstevel@tonic-gate
840Sstevel@tonic-gate sysmopen, /* open */
850Sstevel@tonic-gate sysmclose, /* close */
860Sstevel@tonic-gate nodev, /* strategy */
870Sstevel@tonic-gate nodev, /* print */
880Sstevel@tonic-gate nodev, /* dump */
890Sstevel@tonic-gate sysmread, /* read */
900Sstevel@tonic-gate sysmwrite, /* write */
910Sstevel@tonic-gate sysmioctl, /* ioctl */
920Sstevel@tonic-gate nodev, /* devmap */
930Sstevel@tonic-gate nodev, /* mmap */
940Sstevel@tonic-gate nodev, /* segmap */
950Sstevel@tonic-gate sysmpoll, /* poll */
960Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
970Sstevel@tonic-gate NULL, /* streamtab */
980Sstevel@tonic-gate D_NEW | D_MP, /* Driver compatibility flag */
990Sstevel@tonic-gate CB_REV, /* cb_rev */
1000Sstevel@tonic-gate nodev, /* aread */
1010Sstevel@tonic-gate nodev /* awrite */
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate static struct dev_ops sysm_ops = {
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
1070Sstevel@tonic-gate 0, /* refcnt */
1080Sstevel@tonic-gate sysm_info, /* info */
1090Sstevel@tonic-gate nulldev, /* identify */
1100Sstevel@tonic-gate nulldev, /* probe */
1110Sstevel@tonic-gate sysm_attach, /* attach */
1120Sstevel@tonic-gate sysm_detach, /* detach */
1130Sstevel@tonic-gate nodev, /* reset */
1140Sstevel@tonic-gate &sysm_cb_ops, /* driver operations */
1150Sstevel@tonic-gate (struct bus_ops *)0, /* bus operations */
116*7656SSherry.Moore@Sun.COM nulldev, /* power */
117*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate * Global variables associated with the console device:
1230Sstevel@tonic-gate */
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate #define SYS_SYSMIN 0 /* sysmsg minor number */
1260Sstevel@tonic-gate #define SYS_MSGMIN 1 /* msglog minor number */
1270Sstevel@tonic-gate #define SYSPATHLEN 255 /* length of device path */
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate * Private driver state:
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate #define MAXDEVS 5
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate typedef struct {
1360Sstevel@tonic-gate dev_t dca_devt;
1370Sstevel@tonic-gate int dca_flags;
1380Sstevel@tonic-gate vnode_t *dca_vp;
1390Sstevel@tonic-gate krwlock_t dca_lock;
1400Sstevel@tonic-gate char dca_name[SYSPATHLEN];
1410Sstevel@tonic-gate } devicecache_t;
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /* list of dyn. + persist. config'ed dev's */
1440Sstevel@tonic-gate static devicecache_t sysmcache[MAXDEVS];
1450Sstevel@tonic-gate static kmutex_t dcvp_mutex;
1460Sstevel@tonic-gate static vnode_t *dcvp = NULL;
147742Sfl147353 static boolean_t sysmsg_opened;
148742Sfl147353 static boolean_t msglog_opened;
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate /* flags for device cache */
1510Sstevel@tonic-gate #define SYSM_DISABLED 0x0
1520Sstevel@tonic-gate #define SYSM_ENABLED 0x1
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate * Module linkage information for the kernel.
1560Sstevel@tonic-gate */
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate static struct modldrv modldrv = {
1590Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */
160*7656SSherry.Moore@Sun.COM "System message redirection (fanout) driver",
1610Sstevel@tonic-gate &sysm_ops, /* driver ops */
1620Sstevel@tonic-gate };
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate static struct modlinkage modlinkage = {
1650Sstevel@tonic-gate MODREV_1,
1660Sstevel@tonic-gate &modldrv,
1670Sstevel@tonic-gate NULL
1680Sstevel@tonic-gate };
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate int
_init(void)1710Sstevel@tonic-gate _init(void)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate return (mod_install(&modlinkage));
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate int
_fini(void)1770Sstevel@tonic-gate _fini(void)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate return (mod_remove(&modlinkage));
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1830Sstevel@tonic-gate _info(struct modinfo *modinfop)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate * DDI glue routines
1900Sstevel@tonic-gate */
1910Sstevel@tonic-gate static int
sysm_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)1920Sstevel@tonic-gate sysm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate int i;
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate switch (cmd) {
1970Sstevel@tonic-gate case DDI_ATTACH:
1980Sstevel@tonic-gate ASSERT(sysm_dip == NULL);
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate if (ddi_create_minor_node(devi, "sysmsg", S_IFCHR,
201*7656SSherry.Moore@Sun.COM SYS_SYSMIN, DDI_PSEUDO, NULL) == DDI_FAILURE ||
202*7656SSherry.Moore@Sun.COM ddi_create_minor_node(devi, "msglog", S_IFCHR,
203*7656SSherry.Moore@Sun.COM SYS_MSGMIN, DDI_PSEUDO, NULL) == DDI_FAILURE) {
2040Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL);
2050Sstevel@tonic-gate return (DDI_FAILURE);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
2090Sstevel@tonic-gate rw_init(&sysmcache[i].dca_lock, NULL, RW_DRIVER, NULL);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate sysm_dip = devi;
2130Sstevel@tonic-gate return (DDI_SUCCESS);
2140Sstevel@tonic-gate case DDI_SUSPEND:
2150Sstevel@tonic-gate case DDI_PM_SUSPEND:
2160Sstevel@tonic-gate return (DDI_SUCCESS);
2170Sstevel@tonic-gate default:
2180Sstevel@tonic-gate return (DDI_FAILURE);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate static int
sysm_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)2230Sstevel@tonic-gate sysm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate int i;
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate switch (cmd) {
2280Sstevel@tonic-gate case DDI_DETACH:
2290Sstevel@tonic-gate ASSERT(sysm_dip == devi);
2300Sstevel@tonic-gate
231742Sfl147353 for (i = 0; i < MAXDEVS; i++)
2320Sstevel@tonic-gate rw_destroy(&sysmcache[i].dca_lock);
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL);
2350Sstevel@tonic-gate sysm_dip = NULL;
2360Sstevel@tonic-gate return (DDI_SUCCESS);
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate case DDI_SUSPEND:
2390Sstevel@tonic-gate case DDI_PM_SUSPEND:
2400Sstevel@tonic-gate return (DDI_SUCCESS);
2410Sstevel@tonic-gate default:
2420Sstevel@tonic-gate return (DDI_FAILURE);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /* ARGSUSED */
2480Sstevel@tonic-gate static int
sysm_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2490Sstevel@tonic-gate sysm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2500Sstevel@tonic-gate {
2510Sstevel@tonic-gate int rval = DDI_FAILURE;
2520Sstevel@tonic-gate minor_t instance;
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate instance = getminor((dev_t)arg);
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate switch (infocmd) {
2570Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
2580Sstevel@tonic-gate if (sysm_dip != NULL &&
259*7656SSherry.Moore@Sun.COM (instance == SYS_SYSMIN || instance == SYS_MSGMIN)) {
2600Sstevel@tonic-gate *result = sysm_dip;
2610Sstevel@tonic-gate rval = DDI_SUCCESS;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate break;
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
2660Sstevel@tonic-gate if (instance == SYS_SYSMIN || instance == SYS_MSGMIN) {
2670Sstevel@tonic-gate *result = NULL;
2680Sstevel@tonic-gate rval = DDI_SUCCESS;
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate break;
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate default:
2730Sstevel@tonic-gate break;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate return (rval);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate /*
2800Sstevel@tonic-gate * Parse the contents of the buffer, and bind the named
2810Sstevel@tonic-gate * devices as auxiliary consoles using our own ioctl routine.
2820Sstevel@tonic-gate *
2830Sstevel@tonic-gate * Comments begin with '#' and are terminated only by a newline
2840Sstevel@tonic-gate * Device names begin with a '/', and are terminated by a newline,
2850Sstevel@tonic-gate * space, '#' or tab.
2860Sstevel@tonic-gate */
2870Sstevel@tonic-gate static void
parse_buffer(char * buf,ssize_t fsize)2880Sstevel@tonic-gate parse_buffer(char *buf, ssize_t fsize)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate char *ebuf = buf + fsize;
2910Sstevel@tonic-gate char *devname = NULL;
2920Sstevel@tonic-gate int eatcomments = 0;
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate while (buf < ebuf) {
2950Sstevel@tonic-gate if (eatcomments) {
2960Sstevel@tonic-gate if (*buf++ == '\n')
2970Sstevel@tonic-gate eatcomments = 0;
2980Sstevel@tonic-gate continue;
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate switch (*buf) {
3010Sstevel@tonic-gate case '/':
3020Sstevel@tonic-gate if (devname == NULL)
3030Sstevel@tonic-gate devname = buf;
3040Sstevel@tonic-gate break;
3050Sstevel@tonic-gate case '#':
3060Sstevel@tonic-gate eatcomments = 1;
3070Sstevel@tonic-gate /*FALLTHROUGH*/
3080Sstevel@tonic-gate case ' ':
3090Sstevel@tonic-gate case '\t':
3100Sstevel@tonic-gate case '\n':
3110Sstevel@tonic-gate *buf = '\0';
3120Sstevel@tonic-gate if (devname == NULL)
3130Sstevel@tonic-gate break;
3140Sstevel@tonic-gate (void) sysmioctl(NODEV, CIOCSETCONSOLE,
315*7656SSherry.Moore@Sun.COM (intptr_t)devname, FNATIVE|FKIOCTL|FREAD|FWRITE,
316*7656SSherry.Moore@Sun.COM kcred, NULL);
3170Sstevel@tonic-gate devname = NULL;
3180Sstevel@tonic-gate break;
3190Sstevel@tonic-gate default:
3200Sstevel@tonic-gate break;
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate buf++;
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate #define CNSADM_BYTES_MAX 2000 /* XXX nasty fixed size */
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate static void
bind_consadm_conf(char * path)3290Sstevel@tonic-gate bind_consadm_conf(char *path)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate struct vattr vattr;
3320Sstevel@tonic-gate vnode_t *vp;
3330Sstevel@tonic-gate void *buf;
3340Sstevel@tonic-gate size_t size;
3350Sstevel@tonic-gate ssize_t resid;
3360Sstevel@tonic-gate int err = 0;
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate if (vn_open(path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0) != 0)
3390Sstevel@tonic-gate return;
3400Sstevel@tonic-gate vattr.va_mask = AT_SIZE;
3415331Samw if ((err = VOP_GETATTR(vp, &vattr, 0, kcred, NULL)) != 0) {
3420Sstevel@tonic-gate cmn_err(CE_WARN, "sysmsg: getattr: '%s': error %d",
343*7656SSherry.Moore@Sun.COM path, err);
3440Sstevel@tonic-gate goto closevp;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate size = vattr.va_size > CNSADM_BYTES_MAX ?
348*7656SSherry.Moore@Sun.COM CNSADM_BYTES_MAX : (ssize_t)vattr.va_size;
3490Sstevel@tonic-gate buf = kmem_alloc(size, KM_SLEEP);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate if ((err = vn_rdwr(UIO_READ, vp, buf, size, (offset_t)0,
352*7656SSherry.Moore@Sun.COM UIO_SYSSPACE, 0, (rlim64_t)0, kcred, &resid)) != 0)
3530Sstevel@tonic-gate cmn_err(CE_WARN, "sysmsg: vn_rdwr: '%s': error %d",
3540Sstevel@tonic-gate path, err);
3550Sstevel@tonic-gate else
3560Sstevel@tonic-gate parse_buffer(buf, size - resid);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate kmem_free(buf, size);
3590Sstevel@tonic-gate closevp:
3605331Samw (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, kcred, NULL);
3610Sstevel@tonic-gate VN_RELE(vp);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate /* ARGSUSED */
3650Sstevel@tonic-gate static int
sysmopen(dev_t * dev,int flag,int state,cred_t * cred)3660Sstevel@tonic-gate sysmopen(dev_t *dev, int flag, int state, cred_t *cred)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate int i;
3690Sstevel@tonic-gate vnode_t *vp;
3700Sstevel@tonic-gate minor_t instance;
371742Sfl147353 static boolean_t initialized;
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate instance = getminor(*dev);
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate if (state != OTYP_CHR || (instance != 0 && instance != 1))
3760Sstevel@tonic-gate return (ENXIO);
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate mutex_enter(&dcvp_mutex);
3790Sstevel@tonic-gate if ((dcvp == NULL) && (vn_open("/dev/console",
380*7656SSherry.Moore@Sun.COM UIO_SYSSPACE, FWRITE, 0, &dcvp, 0, 0) != 0)) {
3810Sstevel@tonic-gate mutex_exit(&dcvp_mutex);
3820Sstevel@tonic-gate return (ENXIO);
3830Sstevel@tonic-gate }
384742Sfl147353
385742Sfl147353 if (instance == SYS_SYSMIN)
386742Sfl147353 sysmsg_opened = B_TRUE;
387742Sfl147353 else
388742Sfl147353 msglog_opened = B_TRUE;
389742Sfl147353
390742Sfl147353 if (!initialized) {
391742Sfl147353 bind_consadm_conf("/etc/consadm.conf");
392742Sfl147353 initialized = B_TRUE;
393742Sfl147353 }
3940Sstevel@tonic-gate mutex_exit(&dcvp_mutex);
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
3970Sstevel@tonic-gate rw_enter(&sysmcache[i].dca_lock, RW_WRITER);
3980Sstevel@tonic-gate if ((sysmcache[i].dca_flags & SYSM_ENABLED) &&
399*7656SSherry.Moore@Sun.COM sysmcache[i].dca_vp == NULL) {
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * 4196476 - FTRUNC was causing E10K to return EINVAL
4020Sstevel@tonic-gate * on open
4030Sstevel@tonic-gate */
4040Sstevel@tonic-gate flag = flag & ~FTRUNC;
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate * Open failures on the auxiliary consoles are
4070Sstevel@tonic-gate * not returned because we don't care if some
4080Sstevel@tonic-gate * subset get an error. We know the default console
4090Sstevel@tonic-gate * is okay, and preserve the semantics of the
4100Sstevel@tonic-gate * open for the default console.
4110Sstevel@tonic-gate * Set NONBLOCK|NDELAY in case there's no carrier.
4120Sstevel@tonic-gate */
4130Sstevel@tonic-gate if (vn_open(sysmcache[i].dca_name, UIO_SYSSPACE,
414*7656SSherry.Moore@Sun.COM flag | FNONBLOCK | FNDELAY, 0, &vp, 0, 0) == 0)
4150Sstevel@tonic-gate sysmcache[i].dca_vp = vp;
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate return (0);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /* ARGSUSED */
4240Sstevel@tonic-gate static int
sysmclose(dev_t dev,int flag,int state,cred_t * cred)4250Sstevel@tonic-gate sysmclose(dev_t dev, int flag, int state, cred_t *cred)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate int i;
428742Sfl147353 minor_t instance;
429742Sfl147353
430742Sfl147353 ASSERT(dcvp != NULL);
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate if (state != OTYP_CHR)
4330Sstevel@tonic-gate return (ENXIO);
4340Sstevel@tonic-gate
435742Sfl147353 instance = getminor(dev);
436742Sfl147353
437742Sfl147353 mutex_enter(&dcvp_mutex);
438742Sfl147353 if (instance == SYS_SYSMIN)
439742Sfl147353 sysmsg_opened = B_FALSE;
440742Sfl147353 else
441742Sfl147353 msglog_opened = B_FALSE;
442742Sfl147353
443742Sfl147353 if (sysmsg_opened || msglog_opened) {
444742Sfl147353 mutex_exit(&dcvp_mutex);
445742Sfl147353 return (0);
446742Sfl147353 }
447742Sfl147353
4485331Samw (void) VOP_CLOSE(dcvp, FWRITE, 1, (offset_t)0, kcred, NULL);
449742Sfl147353 VN_RELE(dcvp);
450742Sfl147353 dcvp = NULL;
451742Sfl147353 mutex_exit(&dcvp_mutex);
452742Sfl147353
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate * Close the auxiliary consoles, we're not concerned with
4550Sstevel@tonic-gate * passing up the errors.
4560Sstevel@tonic-gate */
4570Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
4580Sstevel@tonic-gate rw_enter(&sysmcache[i].dca_lock, RW_WRITER);
4590Sstevel@tonic-gate if (sysmcache[i].dca_vp != NULL) {
4600Sstevel@tonic-gate (void) VOP_CLOSE(sysmcache[i].dca_vp, flag,
461*7656SSherry.Moore@Sun.COM 1, (offset_t)0, cred, NULL);
4620Sstevel@tonic-gate VN_RELE(sysmcache[i].dca_vp);
4630Sstevel@tonic-gate sysmcache[i].dca_vp = NULL;
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate return (0);
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate /* Reads occur only on the default console */
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate /* ARGSUSED */
4740Sstevel@tonic-gate static int
sysmread(dev_t dev,struct uio * uio,cred_t * cred)4750Sstevel@tonic-gate sysmread(dev_t dev, struct uio *uio, cred_t *cred)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate ASSERT(dcvp != NULL);
4780Sstevel@tonic-gate return (VOP_READ(dcvp, uio, 0, cred, NULL));
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate /* ARGSUSED */
4820Sstevel@tonic-gate static int
sysmwrite(dev_t dev,struct uio * uio,cred_t * cred)4830Sstevel@tonic-gate sysmwrite(dev_t dev, struct uio *uio, cred_t *cred)
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate int i = 0;
4860Sstevel@tonic-gate iovec_t uio_iov;
4870Sstevel@tonic-gate struct uio tuio;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate ASSERT(dcvp != NULL);
4900Sstevel@tonic-gate ASSERT(uio != NULL);
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
4930Sstevel@tonic-gate rw_enter(&sysmcache[i].dca_lock, RW_READER);
4940Sstevel@tonic-gate if (sysmcache[i].dca_vp != NULL &&
495*7656SSherry.Moore@Sun.COM (sysmcache[i].dca_flags & SYSM_ENABLED)) {
4960Sstevel@tonic-gate tuio = *uio;
4970Sstevel@tonic-gate uio_iov = *(uio->uio_iov);
4980Sstevel@tonic-gate tuio.uio_iov = &uio_iov;
4990Sstevel@tonic-gate (void) VOP_WRITE(sysmcache[i].dca_vp, &tuio, 0, cred,
500*7656SSherry.Moore@Sun.COM NULL);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate return (VOP_WRITE(dcvp, uio, 0, cred, NULL));
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate /* ARGSUSED */
5080Sstevel@tonic-gate static int
sysmioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred,int * rvalp)5090Sstevel@tonic-gate sysmioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred, int *rvalp)
5100Sstevel@tonic-gate {
5110Sstevel@tonic-gate int rval = 0;
5120Sstevel@tonic-gate int error = 0;
5130Sstevel@tonic-gate size_t size = 0;
5140Sstevel@tonic-gate int i;
5150Sstevel@tonic-gate char *infop;
5160Sstevel@tonic-gate char found = 0;
5170Sstevel@tonic-gate dev_t newdevt = (dev_t)NODEV; /* because 0 == /dev/console */
5180Sstevel@tonic-gate vnode_t *vp;
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate switch (cmd) {
5210Sstevel@tonic-gate case CIOCGETCONSOLE:
5220Sstevel@tonic-gate /* Sum over the number of enabled devices */
5230Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
5240Sstevel@tonic-gate if (sysmcache[i].dca_flags & SYSM_ENABLED)
5250Sstevel@tonic-gate /* list is space separated, followed by NULL */
5260Sstevel@tonic-gate size += strlen(sysmcache[i].dca_name) + 1;
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate if (size == 0)
5290Sstevel@tonic-gate return (0);
5300Sstevel@tonic-gate break;
5310Sstevel@tonic-gate case CIOCSETCONSOLE:
5320Sstevel@tonic-gate case CIOCRMCONSOLE:
5330Sstevel@tonic-gate size = sizeof (sysmcache[0].dca_name);
5340Sstevel@tonic-gate break;
5350Sstevel@tonic-gate case CIOCTTYCONSOLE:
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate dev_t d;
5380Sstevel@tonic-gate dev32_t d32;
5390Sstevel@tonic-gate extern dev_t rwsconsdev, rconsdev, uconsdev;
5400Sstevel@tonic-gate proc_t *p;
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate if (drv_getparm(UPROCP, &p) != 0)
5430Sstevel@tonic-gate return (ENODEV);
5440Sstevel@tonic-gate else
5450Sstevel@tonic-gate d = cttydev(p);
5460Sstevel@tonic-gate /*
5470Sstevel@tonic-gate * If the controlling terminal is the real
5480Sstevel@tonic-gate * or workstation console device, map to what the
5490Sstevel@tonic-gate * user thinks is the console device.
5500Sstevel@tonic-gate */
5510Sstevel@tonic-gate if (d == rwsconsdev || d == rconsdev)
5520Sstevel@tonic-gate d = uconsdev;
5530Sstevel@tonic-gate if ((flag & FMODELS) != FNATIVE) {
5540Sstevel@tonic-gate if (!cmpldev(&d32, d))
5550Sstevel@tonic-gate return (EOVERFLOW);
5560Sstevel@tonic-gate if (ddi_copyout(&d32, (caddr_t)arg, sizeof (d32),
5570Sstevel@tonic-gate flag))
5580Sstevel@tonic-gate return (EFAULT);
5590Sstevel@tonic-gate } else {
5600Sstevel@tonic-gate if (ddi_copyout(&d, (caddr_t)arg, sizeof (d), flag))
5610Sstevel@tonic-gate return (EFAULT);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate return (0);
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate default:
5660Sstevel@tonic-gate /* everything else is sent to the console device */
5675331Samw return (VOP_IOCTL(dcvp, cmd, arg, flag, cred, rvalp, NULL));
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate if ((rval = secpolicy_console(cred)) != 0)
5710Sstevel@tonic-gate return (EPERM);
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate infop = kmem_alloc(size, KM_SLEEP);
5740Sstevel@tonic-gate if (flag & FKIOCTL)
5750Sstevel@tonic-gate error = copystr((caddr_t)arg, infop, size, NULL);
5760Sstevel@tonic-gate else
5770Sstevel@tonic-gate error = copyinstr((caddr_t)arg, infop, size, NULL);
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate if (error) {
5800Sstevel@tonic-gate switch (cmd) {
5810Sstevel@tonic-gate case CIOCGETCONSOLE:
5820Sstevel@tonic-gate /*
5830Sstevel@tonic-gate * If the buffer is null, then return a byte count
5840Sstevel@tonic-gate * to user land.
5850Sstevel@tonic-gate */
5860Sstevel@tonic-gate *rvalp = size;
5870Sstevel@tonic-gate goto err_exit;
5880Sstevel@tonic-gate default:
5890Sstevel@tonic-gate rval = EFAULT;
5900Sstevel@tonic-gate goto err_exit;
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate if (infop[0] != NULL) {
5950Sstevel@tonic-gate if ((rval = lookupname(infop, UIO_SYSSPACE, FOLLOW,
596*7656SSherry.Moore@Sun.COM NULLVPP, &vp)) == 0) {
5970Sstevel@tonic-gate if (vp->v_type != VCHR) {
5980Sstevel@tonic-gate VN_RELE(vp);
5990Sstevel@tonic-gate rval = EINVAL;
6000Sstevel@tonic-gate goto err_exit;
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate newdevt = vp->v_rdev;
6030Sstevel@tonic-gate VN_RELE(vp);
6040Sstevel@tonic-gate } else
6050Sstevel@tonic-gate goto err_exit;
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate switch (cmd) {
6090Sstevel@tonic-gate case CIOCGETCONSOLE:
6100Sstevel@tonic-gate /*
6110Sstevel@tonic-gate * Return the list of device names that are enabled.
6120Sstevel@tonic-gate */
6130Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
6140Sstevel@tonic-gate rw_enter(&sysmcache[i].dca_lock, RW_READER);
6150Sstevel@tonic-gate if (sysmcache[i].dca_flags & SYSM_ENABLED) {
6160Sstevel@tonic-gate if (infop[0] != NULL)
6170Sstevel@tonic-gate (void) strcat(infop, " ");
6180Sstevel@tonic-gate (void) strcat(infop, sysmcache[i].dca_name);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate if (rval == 0 && copyoutstr(infop, (void *)arg, size, NULL))
6230Sstevel@tonic-gate rval = EFAULT;
6240Sstevel@tonic-gate break;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate case CIOCSETCONSOLE:
6270Sstevel@tonic-gate if ((rval = checkarg(newdevt)) != 0)
6280Sstevel@tonic-gate break;
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * The device does not have to be open or disabled to
6310Sstevel@tonic-gate * perform the set console.
6320Sstevel@tonic-gate */
6330Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
6340Sstevel@tonic-gate rw_enter(&sysmcache[i].dca_lock, RW_WRITER);
6350Sstevel@tonic-gate if (sysmcache[i].dca_devt == newdevt &&
636*7656SSherry.Moore@Sun.COM (sysmcache[i].dca_flags & SYSM_ENABLED)) {
6370Sstevel@tonic-gate (void) strcpy(sysmcache[i].dca_name, infop);
6380Sstevel@tonic-gate rval = EEXIST;
6390Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6400Sstevel@tonic-gate break;
6410Sstevel@tonic-gate } else if (sysmcache[i].dca_devt == newdevt &&
642*7656SSherry.Moore@Sun.COM sysmcache[i].dca_flags == SYSM_DISABLED) {
6430Sstevel@tonic-gate sysmcache[i].dca_flags |= SYSM_ENABLED;
6440Sstevel@tonic-gate (void) strcpy(sysmcache[i].dca_name, infop);
6450Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6460Sstevel@tonic-gate found = 1;
6470Sstevel@tonic-gate break;
6480Sstevel@tonic-gate } else if (sysmcache[i].dca_devt == 0) {
6490Sstevel@tonic-gate ASSERT(sysmcache[i].dca_vp == NULL &&
650*7656SSherry.Moore@Sun.COM sysmcache[i].dca_flags == SYSM_DISABLED);
6510Sstevel@tonic-gate (void) strcpy(sysmcache[i].dca_name, infop);
6520Sstevel@tonic-gate sysmcache[i].dca_flags = SYSM_ENABLED;
6530Sstevel@tonic-gate sysmcache[i].dca_devt = newdevt;
6540Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6550Sstevel@tonic-gate found = 1;
6560Sstevel@tonic-gate break;
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate if (found == 0 && rval == 0)
6610Sstevel@tonic-gate rval = ENOENT;
6620Sstevel@tonic-gate break;
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate case CIOCRMCONSOLE:
6650Sstevel@tonic-gate for (i = 0; i < MAXDEVS; i++) {
6660Sstevel@tonic-gate rw_enter(&sysmcache[i].dca_lock, RW_WRITER);
6670Sstevel@tonic-gate if (sysmcache[i].dca_devt == newdevt) {
6680Sstevel@tonic-gate sysmcache[i].dca_flags = SYSM_DISABLED;
6690Sstevel@tonic-gate sysmcache[i].dca_name[0] = '\0';
6700Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6710Sstevel@tonic-gate found = 1;
6720Sstevel@tonic-gate break;
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate rw_exit(&sysmcache[i].dca_lock);
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate if (found == 0)
6770Sstevel@tonic-gate rval = ENOENT;
6780Sstevel@tonic-gate break;
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate default:
6810Sstevel@tonic-gate break;
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate err_exit:
6850Sstevel@tonic-gate kmem_free(infop, size);
6860Sstevel@tonic-gate return (rval);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate /* As with the read, we poll only the default console */
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate /* ARGSUSED */
6920Sstevel@tonic-gate static int
sysmpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)6930Sstevel@tonic-gate sysmpoll(dev_t dev, short events, int anyyet, short *reventsp,
6940Sstevel@tonic-gate struct pollhead **phpp)
6950Sstevel@tonic-gate {
6965331Samw return (VOP_POLL(dcvp, events, anyyet, reventsp, phpp, NULL));
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /* Sanity check that the device is good */
7000Sstevel@tonic-gate static int
checkarg(dev_t devt)7010Sstevel@tonic-gate checkarg(dev_t devt)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate int rval = 0;
704742Sfl147353 dev_t sysmsg_dev, msglog_dev;
7050Sstevel@tonic-gate extern dev_t rwsconsdev, rconsdev, uconsdev;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate if (devt == rconsdev || devt == rwsconsdev || devt == uconsdev) {
7080Sstevel@tonic-gate rval = EBUSY;
709742Sfl147353 } else {
710742Sfl147353 sysmsg_dev = makedevice(ddi_driver_major(sysm_dip), SYS_SYSMIN);
711742Sfl147353 msglog_dev = makedevice(ddi_driver_major(sysm_dip), SYS_MSGMIN);
712742Sfl147353 if (devt == sysmsg_dev || devt == msglog_dev)
7130Sstevel@tonic-gate rval = EINVAL;
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate return (rval);
7170Sstevel@tonic-gate }
718