xref: /illumos-gate/usr/src/uts/common/os/logsubr.c (revision bb5c894bdad0d78b8fec5d050bda354c84f7c054)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/varargs.h>
29 #include <sys/systm.h>
30 #include <sys/cmn_err.h>
31 #include <sys/stream.h>
32 #include <sys/strsubr.h>
33 #include <sys/strsun.h>
34 #include <sys/sysmacros.h>
35 #include <sys/kmem.h>
36 #include <sys/log.h>
37 #include <sys/spl.h>
38 #include <sys/syslog.h>
39 #include <sys/console.h>
40 #include <sys/debug.h>
41 #include <sys/utsname.h>
42 #include <sys/id_space.h>
43 #include <sys/zone.h>
44 
45 log_zone_t log_global;
46 queue_t *log_consq;
47 queue_t *log_backlogq;
48 queue_t *log_intrq;
49 
50 #define	LOG_PRISIZE	8	/* max priority size: 7 characters + null */
51 #define	LOG_FACSIZE	9	/* max priority size: 8 characters + null */
52 
53 static krwlock_t log_rwlock;
54 static int log_rwlock_depth;
55 static int log_seq_no[SL_CONSOLE + 1];
56 static stdata_t log_fakestr;
57 static id_space_t *log_minorspace;
58 static log_t log_backlog;
59 static struct kmem_cache *log_cons_cache;	/* log_t cache */
60 
61 static queue_t *log_recentq;
62 static queue_t *log_freeq;
63 
64 static zone_key_t log_zone_key;
65 
66 static char log_overflow_msg[] = "message overflow on /dev/log minor #%d%s\n";
67 
68 static char log_pri[LOG_PRIMASK + 1][LOG_PRISIZE] = {
69 	"emerg",	"alert",	"crit",		"error",
70 	"warning",	"notice",	"info",		"debug"
71 };
72 
73 static char log_fac[LOG_NFACILITIES + 1][LOG_FACSIZE] = {
74 	"kern",		"user",		"mail",		"daemon",
75 	"auth",		"syslog",	"lpr",		"news",
76 	"uucp",		"resv9",	"resv10",	"resv11",
77 	"resv12",	"audit",	"resv14",	"cron",
78 	"local0",	"local1",	"local2",	"local3",
79 	"local4",	"local5",	"local6",	"local7",
80 	"unknown"
81 };
82 static int log_cons_constructor(void *, void *, int);
83 static void log_cons_destructor(void *, void *);
84 
85 /*
86  * Get exclusive access to the logging system; this includes all minor
87  * devices.  We use an rwlock rather than a mutex because hold times
88  * are potentially long, so we don't want to waste cycles in adaptive mutex
89  * spin (rwlocks always block when contended).  Note that we explicitly
90  * support recursive calls (e.g. printf() calls foo() calls printf()).
91  *
92  * Clients may use log_enter() / log_exit() to guarantee that a group
93  * of messages is treated atomically (i.e. they appear in order and are
94  * not interspersed with any other messages), e.g. for multiline printf().
95  *
96  * This could probably be changed to a per-zone lock if contention becomes
97  * an issue.
98  */
99 void
100 log_enter(void)
101 {
102 	if (rw_owner(&log_rwlock) != curthread)
103 		rw_enter(&log_rwlock, RW_WRITER);
104 	log_rwlock_depth++;
105 }
106 
107 void
108 log_exit(void)
109 {
110 	if (--log_rwlock_depth == 0)
111 		rw_exit(&log_rwlock);
112 }
113 
114 void
115 log_flushq(queue_t *q)
116 {
117 	mblk_t *mp;
118 	log_t *lp = (log_t *)q->q_ptr;
119 
120 	/* lp will be NULL if the queue was created via log_makeq */
121 	while ((mp = getq_noenab(q, 0)) != NULL)
122 		log_sendmsg(mp, lp == NULL ? GLOBAL_ZONEID : lp->log_zoneid);
123 }
124 
125 /*
126  * Create a minimal queue with just enough fields filled in to support
127  * canput(9F), putq(9F), and getq_noenab(9F).  We set QNOENB to ensure
128  * that the queue will never be enabled.
129  */
130 static queue_t *
131 log_makeq(size_t lowat, size_t hiwat, void *ibc)
132 {
133 	queue_t *q;
134 
135 	q = kmem_zalloc(sizeof (queue_t), KM_SLEEP);
136 	q->q_stream = &log_fakestr;
137 	q->q_flag = QISDRV | QMTSAFE | QNOENB | QREADR | QUSE;
138 	q->q_nfsrv = q;
139 	q->q_lowat = lowat;
140 	q->q_hiwat = hiwat;
141 	mutex_init(QLOCK(q), NULL, MUTEX_DRIVER, ibc);
142 
143 	return (q);
144 }
145 
146 /*
147  * Initialize the log structure for a new zone.
148  */
149 static void *
150 log_zoneinit(zoneid_t zoneid)
151 {
152 	int i;
153 	log_zone_t *lzp;
154 
155 	if (zoneid == GLOBAL_ZONEID)
156 		lzp = &log_global;	/* use statically allocated struct */
157 	else
158 		lzp = kmem_zalloc(sizeof (log_zone_t), KM_SLEEP);
159 
160 	for (i = 0; i < LOG_NUMCLONES; i++) {
161 		lzp->lz_clones[i].log_minor =
162 		    (minor_t)id_alloc(log_minorspace);
163 		lzp->lz_clones[i].log_zoneid = zoneid;
164 	}
165 	return (lzp);
166 }
167 
168 /*ARGSUSED*/
169 static void
170 log_zonefree(zoneid_t zoneid, void *arg)
171 {
172 	log_zone_t *lzp = arg;
173 	int i;
174 
175 	ASSERT(lzp != &log_global && zoneid != GLOBAL_ZONEID);
176 	if (lzp == NULL)
177 		return;
178 	for (i = 0; i < LOG_NUMCLONES; i++)
179 		id_free(log_minorspace, lzp->lz_clones[i].log_minor);
180 	kmem_free(lzp, sizeof (log_zone_t));
181 }
182 
183 void
184 log_init(void)
185 {
186 	int log_maxzones;
187 
188 	/*
189 	 * Create a backlog queue to consume console messages during periods
190 	 * when there is no console reader (e.g. before syslogd(1M) starts).
191 	 */
192 	log_backlogq = log_consq = log_makeq(0, LOG_HIWAT, NULL);
193 
194 	/*
195 	 * Create a queue to hold free message of size <= LOG_MSGSIZE.
196 	 * Calls from high-level interrupt handlers will do a getq_noenab()
197 	 * from this queue, so its q_lock must be a maximum SPL spin lock.
198 	 */
199 	log_freeq = log_makeq(LOG_MINFREE, LOG_MAXFREE, (void *)ipltospl(SPL8));
200 
201 	/*
202 	 * Create a queue for messages from high-level interrupt context.
203 	 * These messages are drained via softcall, or explicitly by panic().
204 	 */
205 	log_intrq = log_makeq(0, LOG_HIWAT, (void *)ipltospl(SPL8));
206 
207 	/*
208 	 * Create a queue to hold the most recent 8K of console messages.
209 	 * Useful for debugging.  Required by the "$<msgbuf" adb macro.
210 	 */
211 	log_recentq = log_makeq(0, LOG_RECENTSIZE, NULL);
212 
213 	/*
214 	 * Create an id space for clone devices opened via /dev/log.
215 	 * Need to limit the number of zones to avoid exceeding the
216 	 * available minor number space.
217 	 */
218 	log_maxzones = (L_MAXMIN32 - LOG_LOGMIN) / LOG_NUMCLONES - 1;
219 	if (log_maxzones < maxzones)
220 		maxzones = log_maxzones;
221 	log_minorspace = id_space_create("logminor_space", LOG_LOGMIN + 1,
222 	    L_MAXMIN32);
223 	/*
224 	 * Put ourselves on the ZSD list.  Note that zones have not been
225 	 * initialized yet, but our constructor will be called on the global
226 	 * zone when they are.
227 	 */
228 	zone_key_create(&log_zone_key, log_zoneinit, NULL, log_zonefree);
229 
230 	/*
231 	 * Initialize backlog structure.
232 	 */
233 	log_backlog.log_zoneid = GLOBAL_ZONEID;
234 	log_backlog.log_minor = LOG_BACKLOG;
235 
236 	/* Allocate kmem cache for conslog's log structures */
237 	log_cons_cache = kmem_cache_create("log_cons_cache",
238 	    sizeof (struct log), 0, log_cons_constructor, log_cons_destructor,
239 	    NULL, NULL, NULL, 0);
240 
241 	/*
242 	 * Let the logging begin.
243 	 */
244 	log_update(&log_backlog, log_backlogq, SL_CONSOLE, log_console);
245 
246 	/*
247 	 * Now that logging is enabled, emit the SunOS banner.
248 	 */
249 	printf("\rSunOS Release %s Version %s %u-bit\n",
250 	    utsname.release, utsname.version, NBBY * (uint_t)sizeof (void *));
251 	printf("Copyright (c) 1983, 2010, Oracle and/or its affiliates. "
252 	    "All rights reserved.\n");
253 #ifdef DEBUG
254 	printf("DEBUG enabled\n");
255 #endif
256 }
257 
258 /*
259  * Allocate a log device corresponding to supplied device type.
260  * Both devices are clonable. /dev/log devices are allocated per zone.
261  * /dev/conslog devices are allocated from kmem cache.
262  */
263 log_t *
264 log_alloc(minor_t type)
265 {
266 	zone_t *zptr = curproc->p_zone;
267 	log_zone_t *lzp;
268 	log_t *lp;
269 	int i;
270 	minor_t minor;
271 
272 	if (type == LOG_CONSMIN) {
273 
274 		/*
275 		 * Return a write-only /dev/conslog device.
276 		 * No point allocating log_t until there's a free minor number.
277 		 */
278 		minor = (minor_t)id_alloc(log_minorspace);
279 		lp = kmem_cache_alloc(log_cons_cache, KM_SLEEP);
280 		lp->log_minor = minor;
281 		return (lp);
282 	} else {
283 		ASSERT(type == LOG_LOGMIN);
284 
285 		lzp = zone_getspecific(log_zone_key, zptr);
286 		ASSERT(lzp != NULL);
287 
288 		/* search for an available /dev/log device for the zone */
289 		for (i = LOG_LOGMINIDX; i <= LOG_LOGMAXIDX; i++) {
290 			lp = &lzp->lz_clones[i];
291 			if (lp->log_inuse == 0)
292 				break;
293 		}
294 		if (i > LOG_LOGMAXIDX)
295 			lp = NULL;
296 		else
297 			/* Indicate which device type */
298 			lp->log_major = LOG_LOGMIN;
299 		return (lp);
300 	}
301 }
302 
303 void
304 log_free(log_t *lp)
305 {
306 	id_free(log_minorspace, lp->log_minor);
307 	kmem_cache_free(log_cons_cache, lp);
308 }
309 
310 /*
311  * Move console messages from src to dst.  The time of day isn't known
312  * early in boot, so fix up the message timestamps if necessary.
313  */
314 static void
315 log_conswitch(log_t *src, log_t *dst)
316 {
317 	mblk_t *mp;
318 	mblk_t *hmp = NULL;
319 	mblk_t *tmp = NULL;
320 	log_ctl_t *hlc;
321 
322 	while ((mp = getq_noenab(src->log_q, 0)) != NULL) {
323 		log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
324 		lc->flags |= SL_LOGONLY;
325 
326 		/*
327 		 * The ttime is written with 0 in log_sensmsg() only when
328 		 * good gethrestime_sec() data is not available to store in
329 		 * the log_ctl_t in the early boot phase.
330 		 */
331 		if (lc->ttime == 0) {
332 			/*
333 			 * Look ahead to first early boot message with time.
334 			 */
335 			if (hmp) {
336 				tmp->b_next = mp;
337 				tmp = mp;
338 			} else
339 				hmp = tmp = mp;
340 			continue;
341 		}
342 
343 		while (hmp) {
344 			tmp = hmp->b_next;
345 			hmp->b_next = NULL;
346 			hlc = (log_ctl_t *)hmp->b_rptr;
347 			/*
348 			 * Calculate hrestime for an early log message with
349 			 * an invalid time stamp. We know:
350 			 *  - the lbolt of the invalid time stamp.
351 			 *  - the hrestime and lbolt of the first valid
352 			 *    time stamp.
353 			 */
354 			hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz;
355 			(void) putq(dst->log_q, hmp);
356 			hmp = tmp;
357 		}
358 		(void) putq(dst->log_q, mp);
359 	}
360 	while (hmp) {
361 		tmp = hmp->b_next;
362 		hmp->b_next = NULL;
363 		hlc = (log_ctl_t *)hmp->b_rptr;
364 		hlc->ttime = gethrestime_sec() -
365 		    (ddi_get_lbolt() - hlc->ltime) / hz;
366 		(void) putq(dst->log_q, hmp);
367 		hmp = tmp;
368 	}
369 	dst->log_overflow = src->log_overflow;
370 	src->log_flags = 0;
371 	dst->log_flags = SL_CONSOLE;
372 	log_consq = dst->log_q;
373 }
374 
375 /*
376  * Set the fields in the 'target' clone to the specified values.
377  * Then, look at all clones to determine which message types are
378  * currently active and which clone is the primary console queue.
379  * If the primary console queue changes to or from the backlog
380  * queue, copy all messages from backlog to primary or vice versa.
381  */
382 void
383 log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter)
384 {
385 	log_t *lp;
386 	short active = SL_CONSOLE;
387 	zone_t *zptr = NULL;
388 	log_zone_t *lzp;
389 	zoneid_t zoneid = target->log_zoneid;
390 	int i;
391 
392 	log_enter();
393 
394 	if (q != NULL)
395 		target->log_q = q;
396 	target->log_wanted = filter;
397 	target->log_flags = flags;
398 	target->log_overflow = 0;
399 
400 	/*
401 	 * Need to special case the global zone here since this may be
402 	 * called before zone_init.
403 	 */
404 	if (zoneid == GLOBAL_ZONEID) {
405 		lzp = &log_global;
406 	} else if ((zptr = zone_find_by_id(zoneid)) == NULL) {
407 		log_exit();
408 		return;		/* zone is being destroyed, ignore update */
409 	} else {
410 		lzp = zone_getspecific(log_zone_key, zptr);
411 	}
412 	ASSERT(lzp != NULL);
413 	for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) {
414 		lp = &lzp->lz_clones[i];
415 		if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE))
416 			log_consq = lp->log_q;
417 		active |= lp->log_flags;
418 	}
419 	lzp->lz_active = active;
420 
421 	if (zptr)
422 		zone_rele(zptr);
423 
424 	if (log_consq == target->log_q) {
425 		if (flags & SL_CONSOLE)
426 			log_conswitch(&log_backlog, target);
427 		else
428 			log_conswitch(target, &log_backlog);
429 	}
430 	target->log_q = q;
431 
432 	log_exit();
433 }
434 
435 /*ARGSUSED*/
436 int
437 log_error(log_t *lp, log_ctl_t *lc)
438 {
439 	if ((lc->pri & LOG_FACMASK) == LOG_KERN)
440 		lc->pri = LOG_KERN | LOG_ERR;
441 	return (1);
442 }
443 
444 int
445 log_trace(log_t *lp, log_ctl_t *lc)
446 {
447 	trace_ids_t *tid = (trace_ids_t *)lp->log_data->b_rptr;
448 	trace_ids_t *tidend = (trace_ids_t *)lp->log_data->b_wptr;
449 
450 	/*
451 	 * We use `tid + 1 <= tidend' here rather than the more traditional
452 	 * `tid < tidend', since the former ensures that there's at least
453 	 * `sizeof (trace_ids_t)' bytes available before executing the
454 	 * loop, whereas the latter only ensures that there's a single byte.
455 	 */
456 	for (; tid + 1 <= tidend; tid++) {
457 		if (tid->ti_level < lc->level && tid->ti_level >= 0)
458 			continue;
459 		if (tid->ti_mid != lc->mid && tid->ti_mid >= 0)
460 			continue;
461 		if (tid->ti_sid != lc->sid && tid->ti_sid >= 0)
462 			continue;
463 		if ((lc->pri & LOG_FACMASK) == LOG_KERN)
464 			lc->pri = LOG_KERN | LOG_DEBUG;
465 		return (1);
466 	}
467 	return (0);
468 }
469 
470 /*ARGSUSED*/
471 int
472 log_console(log_t *lp, log_ctl_t *lc)
473 {
474 	if ((lc->pri & LOG_FACMASK) == LOG_KERN) {
475 		if (lc->flags & SL_FATAL)
476 			lc->pri = LOG_KERN | LOG_CRIT;
477 		else if (lc->flags & SL_ERROR)
478 			lc->pri = LOG_KERN | LOG_ERR;
479 		else if (lc->flags & SL_WARN)
480 			lc->pri = LOG_KERN | LOG_WARNING;
481 		else if (lc->flags & SL_NOTE)
482 			lc->pri = LOG_KERN | LOG_NOTICE;
483 		else if (lc->flags & SL_TRACE)
484 			lc->pri = LOG_KERN | LOG_DEBUG;
485 		else
486 			lc->pri = LOG_KERN | LOG_INFO;
487 	}
488 	return (1);
489 }
490 
491 mblk_t *
492 log_makemsg(int mid, int sid, int level, int sl, int pri, void *msg,
493 	size_t size, int on_intr)
494 {
495 	mblk_t *mp = NULL;
496 	mblk_t *mp2;
497 	log_ctl_t *lc;
498 
499 	if (size <= LOG_MSGSIZE &&
500 	    (on_intr || log_freeq->q_count > log_freeq->q_lowat))
501 		mp = getq_noenab(log_freeq, 0);
502 
503 	if (mp == NULL) {
504 		if (on_intr ||
505 		    (mp = allocb(sizeof (log_ctl_t), BPRI_HI)) == NULL ||
506 		    (mp2 = allocb(MAX(size, LOG_MSGSIZE), BPRI_HI)) == NULL) {
507 			freemsg(mp);
508 			return (NULL);
509 		}
510 		DB_TYPE(mp) = M_PROTO;
511 		mp->b_wptr += sizeof (log_ctl_t);
512 		mp->b_cont = mp2;
513 	} else {
514 		mp2 = mp->b_cont;
515 		mp2->b_wptr = mp2->b_rptr;
516 	}
517 
518 	lc = (log_ctl_t *)mp->b_rptr;
519 	lc->mid = mid;
520 	lc->sid = sid;
521 	lc->level = level;
522 	lc->flags = sl;
523 	lc->pri = pri;
524 
525 	bcopy(msg, mp2->b_wptr, size - 1);
526 	mp2->b_wptr[size - 1] = '\0';
527 	mp2->b_wptr += strlen((char *)mp2->b_wptr) + 1;
528 
529 	return (mp);
530 }
531 
532 void
533 log_freemsg(mblk_t *mp)
534 {
535 	mblk_t *mp2 = mp->b_cont;
536 
537 	ASSERT(MBLKL(mp) == sizeof (log_ctl_t));
538 	ASSERT(mp2->b_rptr == mp2->b_datap->db_base);
539 
540 	if ((log_freeq->q_flag & QFULL) == 0 &&
541 	    MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE)
542 		(void) putq(log_freeq, mp);
543 	else
544 		freemsg(mp);
545 }
546 
547 void
548 log_sendmsg(mblk_t *mp, zoneid_t zoneid)
549 {
550 	log_t *lp;
551 	char *src, *dst;
552 	mblk_t *mp2 = mp->b_cont;
553 	log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
554 	int flags, fac;
555 	off_t facility = 0;
556 	off_t body = 0;
557 	zone_t *zptr = NULL;
558 	log_zone_t *lzp;
559 	int i;
560 	int backlog;
561 
562 	/*
563 	 * Need to special case the global zone here since this may be
564 	 * called before zone_init.
565 	 */
566 	if (zoneid == GLOBAL_ZONEID) {
567 		lzp = &log_global;
568 	} else if ((zptr = zone_find_by_id(zoneid)) == NULL) {
569 		/* specified zone doesn't exist, free message and return */
570 		log_freemsg(mp);
571 		return;
572 	} else {
573 		lzp = zone_getspecific(log_zone_key, zptr);
574 	}
575 	ASSERT(lzp != NULL);
576 
577 	if ((lc->flags & lzp->lz_active) == 0) {
578 		if (zptr)
579 			zone_rele(zptr);
580 		log_freemsg(mp);
581 		return;
582 	}
583 
584 	if (panicstr) {
585 		/*
586 		 * Raise the console queue's q_hiwat to ensure that we
587 		 * capture all panic messages.
588 		 */
589 		log_consq->q_hiwat = 2 * LOG_HIWAT;
590 		log_consq->q_flag &= ~QFULL;
591 
592 		/* Message was created while panicking. */
593 		lc->flags |= SL_PANICMSG;
594 	}
595 
596 	src = (char *)mp2->b_rptr;
597 	dst = strstr(src, "FACILITY_AND_PRIORITY] ");
598 	if (dst != NULL) {
599 		facility = dst - src;
600 		body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */
601 	}
602 
603 	log_enter();
604 
605 	/*
606 	 * In the early boot phase hrestime is invalid, then timechanged is 0.
607 	 * If hrestime is not valid, the ttime is set to 0 here and the correct
608 	 * ttime is calculated in log_conswitch() later. The log_conswitch()
609 	 * calculation to determine the correct ttime does not use ttime data
610 	 * from these log_ctl_t structures; it only uses ttime from log_ctl_t's
611 	 * that contain good data.
612 	 *
613 	 */
614 	lc->ltime = ddi_get_lbolt();
615 	if (timechanged) {
616 		lc->ttime = gethrestime_sec();
617 	} else {
618 		lc->ttime = 0;
619 	}
620 
621 	flags = lc->flags & lzp->lz_active;
622 	log_seq_no[flags & SL_ERROR]++;
623 	log_seq_no[flags & SL_TRACE]++;
624 	log_seq_no[flags & SL_CONSOLE]++;
625 
626 	/*
627 	 * If this is in the global zone, start with the backlog, then
628 	 * walk through the clone logs.  If not, just do the clone logs.
629 	 */
630 	backlog = (zoneid == GLOBAL_ZONEID);
631 	i = LOG_LOGMINIDX;
632 	while (i <= LOG_LOGMAXIDX) {
633 		if (backlog) {
634 			/*
635 			 * Do the backlog this time, then start on the
636 			 * others.
637 			 */
638 			backlog = 0;
639 			lp = &log_backlog;
640 		} else {
641 			lp = &lzp->lz_clones[i++];
642 		}
643 
644 		if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) {
645 			if (canput(lp->log_q)) {
646 				lp->log_overflow = 0;
647 				lc->seq_no = log_seq_no[lp->log_flags];
648 				if ((mp2 = copymsg(mp)) == NULL)
649 					break;
650 				if (facility != 0) {
651 					src = (char *)mp2->b_cont->b_rptr;
652 					dst = src + facility;
653 					fac = (lc->pri & LOG_FACMASK) >> 3;
654 					dst += snprintf(dst,
655 					    LOG_FACSIZE + LOG_PRISIZE, "%s.%s",
656 					    log_fac[MIN(fac, LOG_NFACILITIES)],
657 					    log_pri[lc->pri & LOG_PRIMASK]);
658 					src += body - 2; /* copy "] " too */
659 					while (*src != '\0')
660 						*dst++ = *src++;
661 					*dst++ = '\0';
662 					mp2->b_cont->b_wptr = (uchar_t *)dst;
663 				}
664 				(void) putq(lp->log_q, mp2);
665 			} else if (++lp->log_overflow == 1) {
666 				if (lp->log_q == log_consq) {
667 					console_printf(log_overflow_msg,
668 					    lp->log_minor,
669 					    " -- is syslogd(1M) running?");
670 				} else {
671 					printf(log_overflow_msg,
672 					    lp->log_minor, "");
673 				}
674 			}
675 		}
676 	}
677 
678 	if (zptr)
679 		zone_rele(zptr);
680 
681 	if ((flags & SL_CONSOLE) && (lc->pri & LOG_FACMASK) == LOG_KERN) {
682 		if ((mp2 == NULL || log_consq == log_backlogq || panicstr) &&
683 		    (lc->flags & SL_LOGONLY) == 0)
684 			console_printf("%s", (char *)mp->b_cont->b_rptr + body);
685 		if ((lc->flags & SL_CONSONLY) == 0 &&
686 		    (mp2 = copymsg(mp)) != NULL) {
687 			mp2->b_cont->b_rptr += body;
688 			if (log_recentq->q_flag & QFULL)
689 				freemsg(getq_noenab(log_recentq, 0));
690 			(void) putq(log_recentq, mp2);
691 		}
692 	}
693 
694 	log_freemsg(mp);
695 
696 	log_exit();
697 }
698 
699 /*
700  * Print queued messages to console.
701  */
702 void
703 log_printq(queue_t *qfirst)
704 {
705 	mblk_t *mp;
706 	queue_t *q, *qlast;
707 	char *cp, *msgp;
708 	log_ctl_t *lc;
709 
710 	/*
711 	 * Look ahead to first queued message in the stream.
712 	 */
713 	qlast = NULL;
714 	do {
715 		for (q = qfirst; q->q_next != qlast; q = q->q_next)
716 			continue;
717 		for (mp = q->q_first; mp != NULL; mp = mp->b_next) {
718 			lc = (log_ctl_t *)mp->b_rptr;
719 			/*
720 			 * Check if message is already displayed at
721 			 * /dev/console.
722 			 */
723 			if (lc->flags & SL_PANICMSG)
724 				continue;
725 
726 			cp = (char *)mp->b_cont->b_rptr;
727 
728 			/* Strip off the message ID. */
729 			if ((msgp = strstr(cp, "[ID ")) != NULL &&
730 			    (msgp = strstr(msgp,  "] ")) != NULL) {
731 				cp = msgp + 2;
732 			}
733 
734 			/*
735 			 * Using console_printf instead of printf to avoid
736 			 * queueing messages to log_consq.
737 			 */
738 			console_printf("%s", cp);
739 		}
740 	} while ((qlast = q) != qfirst);
741 }
742 
743 /* ARGSUSED */
744 static int
745 log_cons_constructor(void *buf, void *cdrarg, int kmflags)
746 {
747 	struct log *lp = buf;
748 
749 	lp->log_zoneid = GLOBAL_ZONEID;
750 	lp->log_major = LOG_CONSMIN;	/* Indicate which device type */
751 	lp->log_data = NULL;
752 	return (0);
753 }
754 
755 /* ARGSUSED */
756 static void
757 log_cons_destructor(void *buf, void *cdrarg)
758 {
759 	struct log *lp = buf;
760 
761 	ASSERT(lp->log_zoneid == GLOBAL_ZONEID);
762 	ASSERT(lp->log_major == LOG_CONSMIN);
763 	ASSERT(lp->log_data == NULL);
764 }
765