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) 2013 Gary Mills
24 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
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", "altcron", "authpriv", "ftp",
78 "ntp", "audit", "console", "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
log_enter(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
log_exit(void)109 log_exit(void)
110 {
111 if (--log_rwlock_depth == 0)
112 rw_exit(&log_rwlock);
113 }
114
115 void
log_flushq(queue_t * q)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 *
log_makeq(size_t lowat,size_t hiwat,void * ibc)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 *
log_zoneinit(zoneid_t zoneid)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
log_zonefree(zoneid_t zoneid,void * arg)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
log_init(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 (c) 1983, 2010, Oracle and/or its affiliates. "
253 "All rights reserved.\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 *
log_alloc(minor_t type)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
log_free(log_t * lp)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
log_conswitch(log_t * src,log_t * dst)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
log_update(log_t * target,queue_t * q,short flags,log_filter_t * filter)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
log_error(log_t * lp,log_ctl_t * lc)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
log_trace(log_t * lp,log_ctl_t * lc)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
log_console(log_t * lp,log_ctl_t * lc)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 *
log_makemsg(int mid,int sid,int level,int sl,int pri,void * msg,size_t size,int on_intr)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
log_freemsg(mblk_t * mp)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
log_sendmsg(mblk_t * mp,zoneid_t zoneid)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
log_printq(queue_t * qfirst)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
log_cons_constructor(void * buf,void * cdrarg,int kmflags)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
log_cons_destructor(void * buf,void * cdrarg)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