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