xref: /titanic_51/usr/src/uts/common/io/log.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Streams log driver.  See log(7D).
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/syslog.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/log.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static dev_info_t *log_devi;	/* private copy of devinfo pointer */
55*7c478bd9Sstevel@tonic-gate int log_msgid;			/* log.conf tunable: enable msgid generation */
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
58*7c478bd9Sstevel@tonic-gate static int
59*7c478bd9Sstevel@tonic-gate log_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
60*7c478bd9Sstevel@tonic-gate {
61*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
62*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
63*7c478bd9Sstevel@tonic-gate 		*result = log_devi;
64*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
65*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
66*7c478bd9Sstevel@tonic-gate 		*result = 0;
67*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
68*7c478bd9Sstevel@tonic-gate 	}
69*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
73*7c478bd9Sstevel@tonic-gate static int
74*7c478bd9Sstevel@tonic-gate log_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
75*7c478bd9Sstevel@tonic-gate {
76*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "conslog", S_IFCHR,
77*7c478bd9Sstevel@tonic-gate 	    LOG_CONSMIN, DDI_PSEUDO, NULL) == DDI_FAILURE ||
78*7c478bd9Sstevel@tonic-gate 	    ddi_create_minor_node(devi, "log", S_IFCHR,
79*7c478bd9Sstevel@tonic-gate 	    LOG_LOGMIN, DDI_PSEUDO, NULL) == DDI_FAILURE) {
80*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
81*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
82*7c478bd9Sstevel@tonic-gate 	}
83*7c478bd9Sstevel@tonic-gate 	log_devi = devi;
84*7c478bd9Sstevel@tonic-gate 	log_msgid = ddi_getprop(DDI_DEV_T_ANY, log_devi,
85*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_CANSLEEP, "msgid", 1);
86*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
87*7c478bd9Sstevel@tonic-gate }
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate /*
90*7c478bd9Sstevel@tonic-gate  * log_open can be called for one of two devices, /dev/conslog or
91*7c478bd9Sstevel@tonic-gate  * /dev/log.  In the case of /dev/conslog it returns the global
92*7c478bd9Sstevel@tonic-gate  * console device (i.e., multiple opens return the same device), while
93*7c478bd9Sstevel@tonic-gate  * for /dev/log a new device is created for each open (up to a limit
94*7c478bd9Sstevel@tonic-gate  * of 16 per zone).  Most of the allocation details are handled in
95*7c478bd9Sstevel@tonic-gate  * log_alloc.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
98*7c478bd9Sstevel@tonic-gate static int
99*7c478bd9Sstevel@tonic-gate log_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *cr)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	log_t *lp;
102*7c478bd9Sstevel@tonic-gate 	minor_t minor;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	if (sflag & (MODOPEN | CLONEOPEN))
105*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	switch (minor = getminor(*devp)) {
108*7c478bd9Sstevel@tonic-gate 	case LOG_CONSMIN:		/* normal open of /dev/conslog */
109*7c478bd9Sstevel@tonic-gate 		if (flag & FREAD)
110*7c478bd9Sstevel@tonic-gate 			return (EINVAL);	/* write-only device */
111*7c478bd9Sstevel@tonic-gate 		if (q->q_ptr)
112*7c478bd9Sstevel@tonic-gate 			return (0);
113*7c478bd9Sstevel@tonic-gate 		break;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	case LOG_LOGMIN:		/* clone open of /dev/log */
116*7c478bd9Sstevel@tonic-gate 		break;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	default:
119*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
120*7c478bd9Sstevel@tonic-gate 	}
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	lp = log_alloc(minor);
123*7c478bd9Sstevel@tonic-gate 	if (lp == NULL)
124*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
125*7c478bd9Sstevel@tonic-gate 	*devp = makedevice(getmajor(*devp), lp->log_minor);
126*7c478bd9Sstevel@tonic-gate 	q->q_ptr = lp;
127*7c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = lp;
128*7c478bd9Sstevel@tonic-gate 	lp->log_inuse = 1;
129*7c478bd9Sstevel@tonic-gate 	qprocson(q);
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	return (0);
132*7c478bd9Sstevel@tonic-gate }
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
135*7c478bd9Sstevel@tonic-gate static int
136*7c478bd9Sstevel@tonic-gate log_close(queue_t *q, int flag, cred_t *cr)
137*7c478bd9Sstevel@tonic-gate {
138*7c478bd9Sstevel@tonic-gate 	log_t *lp = (log_t *)q->q_ptr;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	lp->log_inuse = 0;
143*7c478bd9Sstevel@tonic-gate 	log_update(lp, NULL, 0, NULL);
144*7c478bd9Sstevel@tonic-gate 	freemsg(lp->log_data);
145*7c478bd9Sstevel@tonic-gate 	lp->log_data = NULL;
146*7c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
147*7c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	return (0);
150*7c478bd9Sstevel@tonic-gate }
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate static int
153*7c478bd9Sstevel@tonic-gate log_wput(queue_t *q, mblk_t *mp)
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate 	log_t *lp = (log_t *)q->q_ptr;
156*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
157*7c478bd9Sstevel@tonic-gate 	mblk_t *mp2;
158*7c478bd9Sstevel@tonic-gate 	cred_t *cr = DB_CRED(mp);
159*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	/*
162*7c478bd9Sstevel@tonic-gate 	 * Default to global zone if dblk doesn't have a valid cred.
163*7c478bd9Sstevel@tonic-gate 	 * Calls to syslog() go through putmsg(), which does set up
164*7c478bd9Sstevel@tonic-gate 	 * the cred.
165*7c478bd9Sstevel@tonic-gate 	 */
166*7c478bd9Sstevel@tonic-gate 	zoneid = (cr != NULL) ? crgetzoneid(cr) : GLOBAL_ZONEID;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
169*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
170*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
171*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHALL);
172*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
173*7c478bd9Sstevel@tonic-gate 		}
174*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
175*7c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHALL);
176*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);
177*7c478bd9Sstevel@tonic-gate 			return (0);
178*7c478bd9Sstevel@tonic-gate 		}
179*7c478bd9Sstevel@tonic-gate 		break;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
182*7c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 		if (lp->log_minor <= LOG_LOGMIN) {
185*7c478bd9Sstevel@tonic-gate 			/* not a cloned dev_t */
186*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
187*7c478bd9Sstevel@tonic-gate 			return (0);
188*7c478bd9Sstevel@tonic-gate 		}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count == TRANSPARENT) {
191*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
192*7c478bd9Sstevel@tonic-gate 			return (0);
193*7c478bd9Sstevel@tonic-gate 		}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 		if (lp->log_flags) {
196*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EBUSY);
197*7c478bd9Sstevel@tonic-gate 			return (0);
198*7c478bd9Sstevel@tonic-gate 		}
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 		freemsg(lp->log_data);
201*7c478bd9Sstevel@tonic-gate 		lp->log_data = mp->b_cont;
202*7c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 		case I_CONSLOG:
207*7c478bd9Sstevel@tonic-gate 			log_update(lp, RD(q), SL_CONSOLE, log_console);
208*7c478bd9Sstevel@tonic-gate 			break;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 		case I_TRCLOG:
211*7c478bd9Sstevel@tonic-gate 			if (lp->log_data == NULL) {
212*7c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EINVAL);
213*7c478bd9Sstevel@tonic-gate 				return (0);
214*7c478bd9Sstevel@tonic-gate 			}
215*7c478bd9Sstevel@tonic-gate 			log_update(lp, RD(q), SL_TRACE, log_trace);
216*7c478bd9Sstevel@tonic-gate 			break;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 		case I_ERRLOG:
219*7c478bd9Sstevel@tonic-gate 			log_update(lp, RD(q), SL_ERROR, log_error);
220*7c478bd9Sstevel@tonic-gate 			break;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 		default:
223*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
224*7c478bd9Sstevel@tonic-gate 			return (0);
225*7c478bd9Sstevel@tonic-gate 		}
226*7c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
227*7c478bd9Sstevel@tonic-gate 		return (0);
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
230*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) == sizeof (log_ctl_t) && mp->b_cont != NULL) {
231*7c478bd9Sstevel@tonic-gate 			log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
232*7c478bd9Sstevel@tonic-gate 			/* This code is used by savecore to log dump msgs */
233*7c478bd9Sstevel@tonic-gate 			if (mp->b_band != 0 &&
234*7c478bd9Sstevel@tonic-gate 			    secpolicy_sys_config(CRED(), B_FALSE) == 0) {
235*7c478bd9Sstevel@tonic-gate 				(void) putq(log_consq, mp);
236*7c478bd9Sstevel@tonic-gate 				return (0);
237*7c478bd9Sstevel@tonic-gate 			}
238*7c478bd9Sstevel@tonic-gate 			if ((lc->pri & LOG_FACMASK) == LOG_KERN)
239*7c478bd9Sstevel@tonic-gate 				lc->pri |= LOG_USER;
240*7c478bd9Sstevel@tonic-gate 			mp2 = log_makemsg(LOG_MID, LOG_CONSMIN, lc->level,
241*7c478bd9Sstevel@tonic-gate 			    lc->flags, lc->pri, mp->b_cont->b_rptr,
242*7c478bd9Sstevel@tonic-gate 			    MBLKL(mp->b_cont) + 1, 0);
243*7c478bd9Sstevel@tonic-gate 			if (mp2 != NULL)
244*7c478bd9Sstevel@tonic-gate 				log_sendmsg(mp2, zoneid);
245*7c478bd9Sstevel@tonic-gate 		}
246*7c478bd9Sstevel@tonic-gate 		break;
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	case M_DATA:
249*7c478bd9Sstevel@tonic-gate 		mp2 = log_makemsg(LOG_MID, LOG_CONSMIN, 0, SL_CONSOLE,
250*7c478bd9Sstevel@tonic-gate 		    LOG_USER | LOG_INFO, mp->b_rptr, MBLKL(mp) + 1, 0);
251*7c478bd9Sstevel@tonic-gate 		if (mp2 != NULL)
252*7c478bd9Sstevel@tonic-gate 			log_sendmsg(mp2, zoneid);
253*7c478bd9Sstevel@tonic-gate 		break;
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
257*7c478bd9Sstevel@tonic-gate 	return (0);
258*7c478bd9Sstevel@tonic-gate }
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate static int
261*7c478bd9Sstevel@tonic-gate log_rsrv(queue_t *q)
262*7c478bd9Sstevel@tonic-gate {
263*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
264*7c478bd9Sstevel@tonic-gate 	char *msg, *msgid_start, *msgid_end;
265*7c478bd9Sstevel@tonic-gate 	size_t idlen;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	while (canputnext(q) && (mp = getq(q)) != NULL) {
268*7c478bd9Sstevel@tonic-gate 		if (log_msgid == 0) {
269*7c478bd9Sstevel@tonic-gate 			/*
270*7c478bd9Sstevel@tonic-gate 			 * Strip out the message ID.  If it's a kernel
271*7c478bd9Sstevel@tonic-gate 			 * SL_CONSOLE message, replace msgid with "unix: ".
272*7c478bd9Sstevel@tonic-gate 			 */
273*7c478bd9Sstevel@tonic-gate 			msg = (char *)mp->b_cont->b_rptr;
274*7c478bd9Sstevel@tonic-gate 			if ((msgid_start = strstr(msg, "[ID ")) != NULL &&
275*7c478bd9Sstevel@tonic-gate 			    (msgid_end = strstr(msgid_start, "] ")) != NULL) {
276*7c478bd9Sstevel@tonic-gate 				log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
277*7c478bd9Sstevel@tonic-gate 				if ((lc->flags & SL_CONSOLE) &&
278*7c478bd9Sstevel@tonic-gate 				    (lc->pri & LOG_FACMASK) == LOG_KERN)
279*7c478bd9Sstevel@tonic-gate 					msgid_start = msg + snprintf(msg,
280*7c478bd9Sstevel@tonic-gate 					    7, "unix: ");
281*7c478bd9Sstevel@tonic-gate 				idlen = msgid_end + 2 - msgid_start;
282*7c478bd9Sstevel@tonic-gate 				ovbcopy(msg, msg + idlen, msgid_start - msg);
283*7c478bd9Sstevel@tonic-gate 				mp->b_cont->b_rptr += idlen;
284*7c478bd9Sstevel@tonic-gate 			}
285*7c478bd9Sstevel@tonic-gate 		}
286*7c478bd9Sstevel@tonic-gate 		mp->b_band = 0;
287*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 	return (0);
290*7c478bd9Sstevel@tonic-gate }
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate static struct module_info logm_info =
293*7c478bd9Sstevel@tonic-gate 	{ LOG_MID, "LOG", LOG_MINPS, LOG_MAXPS, LOG_HIWAT, LOG_LOWAT };
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate static struct qinit logrinit =
296*7c478bd9Sstevel@tonic-gate 	{ NULL, log_rsrv, log_open, log_close, NULL, &logm_info, NULL };
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate static struct qinit logwinit =
299*7c478bd9Sstevel@tonic-gate 	{ log_wput, NULL, NULL, NULL, NULL, &logm_info, NULL };
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate static struct streamtab loginfo = { &logrinit, &logwinit, NULL, NULL };
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(log_ops, nulldev, nulldev, log_attach, nodev,
304*7c478bd9Sstevel@tonic-gate 	nodev, log_info, D_NEW | D_MP | D_MTPERMOD, &loginfo);
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv =
307*7c478bd9Sstevel@tonic-gate 	{ &mod_driverops, "streams log driver", &log_ops };
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { MODREV_1, (void *)&modldrv, NULL };
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate int
312*7c478bd9Sstevel@tonic-gate _init()
313*7c478bd9Sstevel@tonic-gate {
314*7c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate int
318*7c478bd9Sstevel@tonic-gate _fini()
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
321*7c478bd9Sstevel@tonic-gate }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate int
324*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
325*7c478bd9Sstevel@tonic-gate {
326*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
327*7c478bd9Sstevel@tonic-gate }
328