4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Streams log driver. See log(7D).
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/errno.h>
34 #include <sys/stropts.h>
35 #include <sys/strsubr.h>
36 #include <sys/stream.h>
37 #include <sys/strsun.h>
38 #include <sys/debug.h>
43 #include <sys/syslog.h>
45 #include <sys/systm.h>
46 #include <sys/modctl.h>
47 #include <sys/policy.h>
51 #include <sys/sunddi.h>
53 static dev_info_t
*log_devi
; /* private copy of devinfo pointer */
54 int log_msgid
; /* log.conf tunable: enable msgid generation */
58 log_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
61 case DDI_INFO_DEVT2DEVINFO
:
64 case DDI_INFO_DEVT2INSTANCE
:
73 log_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
75 if (ddi_create_minor_node(devi
, "conslog", S_IFCHR
,
76 LOG_CONSMIN
, DDI_PSEUDO
, 0) == DDI_FAILURE
||
77 ddi_create_minor_node(devi
, "log", S_IFCHR
,
78 LOG_LOGMIN
, DDI_PSEUDO
, 0) == DDI_FAILURE
) {
79 ddi_remove_minor_node(devi
, NULL
);
83 log_msgid
= ddi_getprop(DDI_DEV_T_ANY
, log_devi
,
84 DDI_PROP_CANSLEEP
, "msgid", 1);
89 * log_open can be called for either /dev/log or dev/conslog.
91 * In the /dev/conslog case log_alloc() allocates a new minor device from
94 * In the case of /dev/log, LOG_NUMCLONES devices are pre-allocated at zone
95 * creation. log_alloc() finds the zone's next available minor device.
97 * On entry devp's minor number indicates which device (log or conslog), on
98 * successful return it is the device instance.
103 log_open(queue_t
*q
, dev_t
*devp
, int flag
, int sflag
, cred_t
*cr
)
108 if (sflag
& (MODOPEN
| CLONEOPEN
))
111 switch (minor
= getminor(*devp
)) {
112 case LOG_CONSMIN
: /* clone open of /dev/conslog */
114 return (EINVAL
); /* write-only device */
119 case LOG_LOGMIN
: /* clone open of /dev/log */
126 lp
= log_alloc(minor
);
129 *devp
= makedevice(getmajor(*devp
), lp
->log_minor
);
140 log_close(queue_t
*q
, int flag
, cred_t
*cr
)
142 log_t
*lp
= (log_t
*)q
->q_ptr
;
147 log_update(lp
, NULL
, 0, NULL
);
148 freemsg(lp
->log_data
);
150 if (lp
->log_major
== LOG_CONSMIN
)
159 log_wput(queue_t
*q
, mblk_t
*mp
)
161 log_t
*lp
= (log_t
*)q
->q_ptr
;
164 cred_t
*cr
= msg_getcred(mp
, NULL
);
168 * Default to global zone if dblk doesn't have a valid cred.
169 * Calls to syslog() go through putmsg(), which does set up
172 zoneid
= (cr
!= NULL
) ? crgetzoneid(cr
) : GLOBAL_ZONEID
;
174 switch (DB_TYPE(mp
)) {
176 if (*mp
->b_rptr
& FLUSHW
) {
178 *mp
->b_rptr
&= ~FLUSHW
;
180 if (*mp
->b_rptr
& FLUSHR
) {
181 flushq(RD(q
), FLUSHALL
);
188 iocp
= (struct iocblk
*)mp
->b_rptr
;
190 if (lp
->log_major
!= LOG_LOGMIN
) {
191 /* write-only device */
192 miocnak(q
, mp
, 0, EINVAL
);
196 if (iocp
->ioc_count
== TRANSPARENT
) {
197 miocnak(q
, mp
, 0, EINVAL
);
202 miocnak(q
, mp
, 0, EBUSY
);
206 freemsg(lp
->log_data
);
207 lp
->log_data
= mp
->b_cont
;
210 switch (iocp
->ioc_cmd
) {
213 log_update(lp
, RD(q
), SL_CONSOLE
, log_console
);
217 if (lp
->log_data
== NULL
) {
218 miocnak(q
, mp
, 0, EINVAL
);
221 log_update(lp
, RD(q
), SL_TRACE
, log_trace
);
225 log_update(lp
, RD(q
), SL_ERROR
, log_error
);
229 miocnak(q
, mp
, 0, EINVAL
);
232 miocack(q
, mp
, 0, 0);
236 if (MBLKL(mp
) == sizeof (log_ctl_t
) && mp
->b_cont
!= NULL
) {
237 log_ctl_t
*lc
= (log_ctl_t
*)mp
->b_rptr
;
238 /* This code is used by savecore to log dump msgs */
239 if (mp
->b_band
!= 0 &&
240 secpolicy_sys_config(CRED(), B_FALSE
) == 0) {
241 (void) putq(log_consq
, mp
);
244 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
)
246 mp2
= log_makemsg(LOG_MID
, LOG_CONSMIN
, lc
->level
,
247 lc
->flags
, lc
->pri
, mp
->b_cont
->b_rptr
,
248 MBLKL(mp
->b_cont
) + 1, 0);
250 log_sendmsg(mp2
, zoneid
);
255 mp2
= log_makemsg(LOG_MID
, LOG_CONSMIN
, 0, SL_CONSOLE
,
256 LOG_USER
| LOG_INFO
, mp
->b_rptr
, MBLKL(mp
) + 1, 0);
258 log_sendmsg(mp2
, zoneid
);
270 char *msg
, *msgid_start
, *msgid_end
;
273 while (canputnext(q
) && (mp
= getq(q
)) != NULL
) {
274 if (log_msgid
== 0) {
276 * Strip out the message ID. If it's a kernel
277 * SL_CONSOLE message, replace msgid with "unix: ".
279 msg
= (char *)mp
->b_cont
->b_rptr
;
280 if ((msgid_start
= strstr(msg
, "[ID ")) != NULL
&&
281 (msgid_end
= strstr(msgid_start
, "] ")) != NULL
) {
282 log_ctl_t
*lc
= (log_ctl_t
*)mp
->b_rptr
;
283 if ((lc
->flags
& SL_CONSOLE
) &&
284 (lc
->pri
& LOG_FACMASK
) == LOG_KERN
)
285 msgid_start
= msg
+ snprintf(msg
,
287 idlen
= msgid_end
+ 2 - msgid_start
;
288 ovbcopy(msg
, msg
+ idlen
, msgid_start
- msg
);
289 mp
->b_cont
->b_rptr
+= idlen
;
298 static struct module_info logm_info
=
299 { LOG_MID
, "LOG", LOG_MINPS
, LOG_MAXPS
, LOG_HIWAT
, LOG_LOWAT
};
301 static struct qinit logrinit
=
302 { NULL
, log_rsrv
, log_open
, log_close
, NULL
, &logm_info
, NULL
};
304 static struct qinit logwinit
=
305 { log_wput
, NULL
, NULL
, NULL
, NULL
, &logm_info
, NULL
};
307 static struct streamtab loginfo
= { &logrinit
, &logwinit
, NULL
, NULL
};
309 DDI_DEFINE_STREAM_OPS(log_ops
, nulldev
, nulldev
, log_attach
, nodev
, nodev
,
310 log_info
, D_NEW
| D_MP
| D_MTPERMOD
, &loginfo
, ddi_quiesce_not_needed
);
312 static struct modldrv modldrv
=
313 { &mod_driverops
, "streams log driver", &log_ops
};
315 static struct modlinkage modlinkage
= { MODREV_1
, (void *)&modldrv
, NULL
};
320 return (mod_install(&modlinkage
));
326 return (mod_remove(&modlinkage
));
330 _info(struct modinfo
*modinfop
)
332 return (mod_info(&modlinkage
, modinfop
));