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