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