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 2020 Oxide Computer Company
24 * Copyright (c) 2013 Gary Mills
25 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
26 */
27
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/varargs.h>
31 #include <sys/systm.h>
32 #include <sys/cmn_err.h>
33 #include <sys/stream.h>
34 #include <sys/strsubr.h>
35 #include <sys/strsun.h>
36 #include <sys/sysmacros.h>
37 #include <sys/kmem.h>
38 #include <sys/log.h>
39 #include <sys/spl.h>
40 #include <sys/syslog.h>
41 #include <sys/console.h>
42 #include <sys/debug.h>
43 #include <sys/utsname.h>
44 #include <sys/id_space.h>
45 #include <sys/zone.h>
46 #include <sys/bootbanner.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", "altcron", "authpriv", "ftp",
80 "ntp", "audit", "console", "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
log_enter(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
log_exit(void)111 log_exit(void)
112 {
113 if (--log_rwlock_depth == 0)
114 rw_exit(&log_rwlock);
115 }
116
117 void
log_flushq(queue_t * q)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 *
log_makeq(size_t lowat,size_t hiwat,void * ibc)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 *
log_zoneinit(zoneid_t zoneid)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
log_zonefree(zoneid_t zoneid,void * arg)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 static void
log_bootbanner_print(const char * line,uint_t num)187 log_bootbanner_print(const char *line, uint_t num)
188 {
189 const char *pfx = (num == 0) ? "\r" : "";
190
191 printf("%s%s\n", pfx, line);
192 }
193
194 void
log_init(void)195 log_init(void)
196 {
197 int log_maxzones;
198
199 /*
200 * Create a backlog queue to consume console messages during periods
201 * when there is no console reader (e.g. before syslogd(8) starts).
202 */
203 log_backlogq = log_consq = log_makeq(0, LOG_HIWAT, NULL);
204
205 /*
206 * Create a queue to hold free message of size <= LOG_MSGSIZE.
207 * Calls from high-level interrupt handlers will do a getq_noenab()
208 * from this queue, so its q_lock must be a maximum SPL spin lock.
209 */
210 log_freeq = log_makeq(LOG_MINFREE, LOG_MAXFREE, (void *)ipltospl(SPL8));
211
212 /*
213 * Create a queue for messages from high-level interrupt context.
214 * These messages are drained via softcall, or explicitly by panic().
215 */
216 log_intrq = log_makeq(0, LOG_HIWAT, (void *)ipltospl(SPL8));
217
218 /*
219 * Create a queue to hold the most recent 64K of console messages.
220 * Useful for debugging. Required by the "$<msgbuf" adb macro.
221 */
222 log_recentq = log_makeq(0, LOG_RECENTSIZE, NULL);
223
224 /*
225 * Create an id space for clone devices opened via /dev/log.
226 * Need to limit the number of zones to avoid exceeding the
227 * available minor number space.
228 */
229 log_maxzones = (L_MAXMIN32 - LOG_LOGMIN) / LOG_NUMCLONES - 1;
230 if (log_maxzones < maxzones)
231 maxzones = log_maxzones;
232 log_minorspace = id_space_create("logminor_space", LOG_LOGMIN + 1,
233 L_MAXMIN32);
234 /*
235 * Put ourselves on the ZSD list. Note that zones have not been
236 * initialized yet, but our constructor will be called on the global
237 * zone when they are.
238 */
239 zone_key_create(&log_zone_key, log_zoneinit, NULL, log_zonefree);
240
241 /*
242 * Initialize backlog structure.
243 */
244 log_backlog.log_zoneid = GLOBAL_ZONEID;
245 log_backlog.log_minor = LOG_BACKLOG;
246
247 /* Allocate kmem cache for conslog's log structures */
248 log_cons_cache = kmem_cache_create("log_cons_cache",
249 sizeof (struct log), 0, log_cons_constructor, log_cons_destructor,
250 NULL, NULL, NULL, 0);
251
252 /*
253 * Let the logging begin.
254 */
255 log_update(&log_backlog, log_backlogq, SL_CONSOLE, log_console);
256
257 /*
258 * Now that logging is enabled, emit the boot banner.
259 */
260 #ifdef LEGACY_BANNER
261 printf("\rSunOS Release %s Version %s %u-bit\n",
262 utsname.release, utsname.version, NBBY * (uint_t)sizeof (void *));
263 printf("Copyright (c) 1983, 2010, Oracle and/or its affiliates. "
264 "All rights reserved.\n");
265 #else
266 bootbanner_print(log_bootbanner_print);
267 #endif
268 #ifdef DEBUG
269 printf("DEBUG enabled\n");
270 #endif
271 }
272
273 /*
274 * Allocate a log device corresponding to supplied device type.
275 * Both devices are clonable. /dev/log devices are allocated per zone.
276 * /dev/conslog devices are allocated from kmem cache.
277 */
278 log_t *
log_alloc(minor_t type)279 log_alloc(minor_t type)
280 {
281 zone_t *zptr = curproc->p_zone;
282 log_zone_t *lzp;
283 log_t *lp;
284 int i;
285 minor_t minor;
286
287 if (type == LOG_CONSMIN) {
288
289 /*
290 * Return a write-only /dev/conslog device.
291 * No point allocating log_t until there's a free minor number.
292 */
293 minor = (minor_t)id_alloc(log_minorspace);
294 lp = kmem_cache_alloc(log_cons_cache, KM_SLEEP);
295 lp->log_minor = minor;
296 return (lp);
297 } else {
298 ASSERT(type == LOG_LOGMIN);
299
300 lzp = zone_getspecific(log_zone_key, zptr);
301 ASSERT(lzp != NULL);
302
303 /* search for an available /dev/log device for the zone */
304 for (i = LOG_LOGMINIDX; i <= LOG_LOGMAXIDX; i++) {
305 lp = &lzp->lz_clones[i];
306 if (lp->log_inuse == 0)
307 break;
308 }
309 if (i > LOG_LOGMAXIDX)
310 lp = NULL;
311 else
312 /* Indicate which device type */
313 lp->log_major = LOG_LOGMIN;
314 return (lp);
315 }
316 }
317
318 void
log_free(log_t * lp)319 log_free(log_t *lp)
320 {
321 id_free(log_minorspace, lp->log_minor);
322 kmem_cache_free(log_cons_cache, lp);
323 }
324
325 /*
326 * Move console messages from src to dst. The time of day isn't known
327 * early in boot, so fix up the message timestamps if necessary.
328 */
329 static void
log_conswitch(log_t * src,log_t * dst)330 log_conswitch(log_t *src, log_t *dst)
331 {
332 mblk_t *mp;
333 mblk_t *hmp = NULL;
334 mblk_t *tmp = NULL;
335 log_ctl_t *hlc;
336
337 while ((mp = getq_noenab(src->log_q, 0)) != NULL) {
338 log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
339 lc->flags |= SL_LOGONLY;
340
341 /*
342 * The ttime is written with 0 in log_sensmsg() only when
343 * good gethrestime_sec() data is not available to store in
344 * the log_ctl_t in the early boot phase.
345 */
346 if (lc->ttime == 0) {
347 /*
348 * Look ahead to first early boot message with time.
349 */
350 if (hmp) {
351 tmp->b_next = mp;
352 tmp = mp;
353 } else
354 hmp = tmp = mp;
355 continue;
356 }
357
358 while (hmp) {
359 tmp = hmp->b_next;
360 hmp->b_next = NULL;
361 hlc = (log_ctl_t *)hmp->b_rptr;
362 /*
363 * Calculate hrestime for an early log message with
364 * an invalid time stamp. We know:
365 * - the lbolt of the invalid time stamp.
366 * - the hrestime and lbolt of the first valid
367 * time stamp.
368 */
369 hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz;
370 (void) putq(dst->log_q, hmp);
371 hmp = tmp;
372 }
373 (void) putq(dst->log_q, mp);
374 }
375 while (hmp) {
376 tmp = hmp->b_next;
377 hmp->b_next = NULL;
378 hlc = (log_ctl_t *)hmp->b_rptr;
379 hlc->ttime = gethrestime_sec() -
380 (ddi_get_lbolt() - hlc->ltime) / hz;
381 (void) putq(dst->log_q, hmp);
382 hmp = tmp;
383 }
384 dst->log_overflow = src->log_overflow;
385 src->log_flags = 0;
386 dst->log_flags = SL_CONSOLE;
387 log_consq = dst->log_q;
388 }
389
390 /*
391 * Set the fields in the 'target' clone to the specified values.
392 * Then, look at all clones to determine which message types are
393 * currently active and which clone is the primary console queue.
394 * If the primary console queue changes to or from the backlog
395 * queue, copy all messages from backlog to primary or vice versa.
396 */
397 void
log_update(log_t * target,queue_t * q,short flags,log_filter_t * filter)398 log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter)
399 {
400 log_t *lp;
401 short active = SL_CONSOLE;
402 zone_t *zptr = NULL;
403 log_zone_t *lzp;
404 zoneid_t zoneid = target->log_zoneid;
405 int i;
406
407 log_enter();
408
409 if (q != NULL)
410 target->log_q = q;
411 target->log_wanted = filter;
412 target->log_flags = flags;
413 target->log_overflow = 0;
414
415 /*
416 * Need to special case the global zone here since this may be
417 * called before zone_init.
418 */
419 if (zoneid == GLOBAL_ZONEID) {
420 lzp = &log_global;
421 } else if ((zptr = zone_find_by_id(zoneid)) == NULL) {
422 log_exit();
423 return; /* zone is being destroyed, ignore update */
424 } else {
425 lzp = zone_getspecific(log_zone_key, zptr);
426 }
427 ASSERT(lzp != NULL);
428 for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) {
429 lp = &lzp->lz_clones[i];
430 if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE))
431 log_consq = lp->log_q;
432 active |= lp->log_flags;
433 }
434 lzp->lz_active = active;
435
436 if (zptr)
437 zone_rele(zptr);
438
439 if (log_consq == target->log_q) {
440 if (flags & SL_CONSOLE)
441 log_conswitch(&log_backlog, target);
442 else
443 log_conswitch(target, &log_backlog);
444 }
445 target->log_q = q;
446
447 log_exit();
448 }
449
450 /*ARGSUSED*/
451 int
log_error(log_t * lp,log_ctl_t * lc)452 log_error(log_t *lp, log_ctl_t *lc)
453 {
454 if ((lc->pri & LOG_FACMASK) == LOG_KERN)
455 lc->pri = LOG_KERN | LOG_ERR;
456 return (1);
457 }
458
459 int
log_trace(log_t * lp,log_ctl_t * lc)460 log_trace(log_t *lp, log_ctl_t *lc)
461 {
462 trace_ids_t *tid = (trace_ids_t *)lp->log_data->b_rptr;
463 trace_ids_t *tidend = (trace_ids_t *)lp->log_data->b_wptr;
464
465 /*
466 * We use `tid + 1 <= tidend' here rather than the more traditional
467 * `tid < tidend', since the former ensures that there's at least
468 * `sizeof (trace_ids_t)' bytes available before executing the
469 * loop, whereas the latter only ensures that there's a single byte.
470 */
471 for (; tid + 1 <= tidend; tid++) {
472 if (tid->ti_level < lc->level && tid->ti_level >= 0)
473 continue;
474 if (tid->ti_mid != lc->mid && tid->ti_mid >= 0)
475 continue;
476 if (tid->ti_sid != lc->sid && tid->ti_sid >= 0)
477 continue;
478 if ((lc->pri & LOG_FACMASK) == LOG_KERN)
479 lc->pri = LOG_KERN | LOG_DEBUG;
480 return (1);
481 }
482 return (0);
483 }
484
485 /*ARGSUSED*/
486 int
log_console(log_t * lp,log_ctl_t * lc)487 log_console(log_t *lp, log_ctl_t *lc)
488 {
489 if ((lc->pri & LOG_FACMASK) == LOG_KERN) {
490 if (lc->flags & SL_FATAL)
491 lc->pri = LOG_KERN | LOG_CRIT;
492 else if (lc->flags & SL_ERROR)
493 lc->pri = LOG_KERN | LOG_ERR;
494 else if (lc->flags & SL_WARN)
495 lc->pri = LOG_KERN | LOG_WARNING;
496 else if (lc->flags & SL_NOTE)
497 lc->pri = LOG_KERN | LOG_NOTICE;
498 else if (lc->flags & SL_TRACE)
499 lc->pri = LOG_KERN | LOG_DEBUG;
500 else
501 lc->pri = LOG_KERN | LOG_INFO;
502 }
503 return (1);
504 }
505
506 mblk_t *
log_makemsg(int mid,int sid,int level,int sl,int pri,void * msg,size_t size,int on_intr)507 log_makemsg(int mid, int sid, int level, int sl, int pri, void *msg,
508 size_t size, int on_intr)
509 {
510 mblk_t *mp = NULL;
511 mblk_t *mp2;
512 log_ctl_t *lc;
513
514 if (size <= LOG_MSGSIZE &&
515 (on_intr || log_freeq->q_count > log_freeq->q_lowat))
516 mp = getq_noenab(log_freeq, 0);
517
518 if (mp == NULL) {
519 if (on_intr ||
520 (mp = allocb(sizeof (log_ctl_t), BPRI_HI)) == NULL ||
521 (mp2 = allocb(MAX(size, LOG_MSGSIZE), BPRI_HI)) == NULL) {
522 freemsg(mp);
523 return (NULL);
524 }
525 DB_TYPE(mp) = M_PROTO;
526 mp->b_wptr += sizeof (log_ctl_t);
527 mp->b_cont = mp2;
528 } else {
529 mp2 = mp->b_cont;
530 mp2->b_wptr = mp2->b_rptr;
531 }
532
533 lc = (log_ctl_t *)mp->b_rptr;
534 lc->mid = mid;
535 lc->sid = sid;
536 lc->level = level;
537 lc->flags = sl;
538 lc->pri = pri;
539
540 bcopy(msg, mp2->b_wptr, size - 1);
541 mp2->b_wptr[size - 1] = '\0';
542 mp2->b_wptr += strlen((char *)mp2->b_wptr) + 1;
543
544 return (mp);
545 }
546
547 void
log_freemsg(mblk_t * mp)548 log_freemsg(mblk_t *mp)
549 {
550 mblk_t *mp2 = mp->b_cont;
551
552 ASSERT(MBLKL(mp) == sizeof (log_ctl_t));
553 ASSERT(mp2->b_rptr == mp2->b_datap->db_base);
554
555 if ((log_freeq->q_flag & QFULL) == 0 &&
556 MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE)
557 (void) putq(log_freeq, mp);
558 else
559 freemsg(mp);
560 }
561
562 void
log_sendmsg(mblk_t * mp,zoneid_t zoneid)563 log_sendmsg(mblk_t *mp, zoneid_t zoneid)
564 {
565 log_t *lp;
566 char *src, *dst;
567 mblk_t *mp2 = mp->b_cont;
568 log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
569 int flags, fac;
570 off_t facility = 0;
571 off_t body = 0;
572 zone_t *zptr = NULL;
573 log_zone_t *lzp;
574 int i;
575 int backlog;
576
577 /*
578 * Need to special case the global zone here since this may be
579 * called before zone_init.
580 */
581 if (zoneid == GLOBAL_ZONEID) {
582 lzp = &log_global;
583 } else if ((zptr = zone_find_by_id(zoneid)) == NULL) {
584 /* specified zone doesn't exist, free message and return */
585 log_freemsg(mp);
586 return;
587 } else {
588 lzp = zone_getspecific(log_zone_key, zptr);
589 }
590 ASSERT(lzp != NULL);
591
592 if ((lc->flags & lzp->lz_active) == 0) {
593 if (zptr)
594 zone_rele(zptr);
595 log_freemsg(mp);
596 return;
597 }
598
599 if (panicstr) {
600 /*
601 * Raise the console queue's q_hiwat to ensure that we
602 * capture all panic messages.
603 */
604 log_consq->q_hiwat = 2 * LOG_HIWAT;
605 log_consq->q_flag &= ~QFULL;
606
607 /* Message was created while panicking. */
608 lc->flags |= SL_PANICMSG;
609 }
610
611 src = (char *)mp2->b_rptr;
612 dst = strstr(src, "FACILITY_AND_PRIORITY] ");
613 if (dst != NULL) {
614 facility = dst - src;
615 body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */
616 }
617
618 log_enter();
619
620 /*
621 * In the early boot phase hrestime is invalid, then timechanged is 0.
622 * If hrestime is not valid, the ttime is set to 0 here and the correct
623 * ttime is calculated in log_conswitch() later. The log_conswitch()
624 * calculation to determine the correct ttime does not use ttime data
625 * from these log_ctl_t structures; it only uses ttime from log_ctl_t's
626 * that contain good data.
627 *
628 */
629 lc->ltime = ddi_get_lbolt();
630 if (timechanged) {
631 lc->ttime = gethrestime_sec();
632 } else {
633 lc->ttime = 0;
634 }
635
636 flags = lc->flags & lzp->lz_active;
637 log_seq_no[flags & SL_ERROR]++;
638 log_seq_no[flags & SL_TRACE]++;
639 log_seq_no[flags & SL_CONSOLE]++;
640
641 /*
642 * If this is in the global zone, start with the backlog, then
643 * walk through the clone logs. If not, just do the clone logs.
644 */
645 backlog = (zoneid == GLOBAL_ZONEID);
646 i = LOG_LOGMINIDX;
647 while (i <= LOG_LOGMAXIDX) {
648 if (backlog) {
649 /*
650 * Do the backlog this time, then start on the
651 * others.
652 */
653 backlog = 0;
654 lp = &log_backlog;
655 } else {
656 lp = &lzp->lz_clones[i++];
657 }
658
659 if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) {
660 if (canput(lp->log_q)) {
661 lp->log_overflow = 0;
662 lc->seq_no = log_seq_no[lp->log_flags];
663 if ((mp2 = copymsg(mp)) == NULL)
664 break;
665 if (facility != 0) {
666 src = (char *)mp2->b_cont->b_rptr;
667 dst = src + facility;
668 fac = (lc->pri & LOG_FACMASK) >> 3;
669 dst += snprintf(dst,
670 LOG_FACSIZE + LOG_PRISIZE, "%s.%s",
671 log_fac[MIN(fac, LOG_NFACILITIES)],
672 log_pri[lc->pri & LOG_PRIMASK]);
673 src += body - 2; /* copy "] " too */
674 while (*src != '\0')
675 *dst++ = *src++;
676 *dst++ = '\0';
677 mp2->b_cont->b_wptr = (uchar_t *)dst;
678 }
679 (void) putq(lp->log_q, mp2);
680 } else if (++lp->log_overflow == 1) {
681 if (lp->log_q == log_consq) {
682 console_printf(log_overflow_msg,
683 lp->log_minor,
684 " -- is syslogd(8) running?");
685 } else {
686 printf(log_overflow_msg,
687 lp->log_minor, "");
688 }
689 }
690 }
691 }
692
693 if (zptr)
694 zone_rele(zptr);
695
696 if ((flags & SL_CONSOLE) && (lc->pri & LOG_FACMASK) == LOG_KERN) {
697 if ((mp2 == NULL || log_consq == log_backlogq || panicstr) &&
698 (lc->flags & SL_LOGONLY) == 0)
699 console_printf("%s", (char *)mp->b_cont->b_rptr + body);
700 if ((lc->flags & SL_CONSONLY) == 0 &&
701 (mp2 = copymsg(mp)) != NULL) {
702 mp2->b_cont->b_rptr += body;
703 if (log_recentq->q_flag & QFULL)
704 freemsg(getq_noenab(log_recentq, 0));
705 (void) putq(log_recentq, mp2);
706 }
707 }
708
709 log_freemsg(mp);
710
711 log_exit();
712 }
713
714 /*
715 * Print queued messages to console.
716 */
717 void
log_printq(queue_t * qfirst)718 log_printq(queue_t *qfirst)
719 {
720 mblk_t *mp;
721 queue_t *q, *qlast;
722 char *cp, *msgp;
723 log_ctl_t *lc;
724
725 /*
726 * Look ahead to first queued message in the stream.
727 */
728 qlast = NULL;
729 do {
730 for (q = qfirst; q->q_next != qlast; q = q->q_next)
731 continue;
732 for (mp = q->q_first; mp != NULL; mp = mp->b_next) {
733 lc = (log_ctl_t *)mp->b_rptr;
734 /*
735 * Check if message is already displayed at
736 * /dev/console.
737 */
738 if (lc->flags & SL_PANICMSG)
739 continue;
740
741 cp = (char *)mp->b_cont->b_rptr;
742
743 /* Strip off the message ID. */
744 if ((msgp = strstr(cp, "[ID ")) != NULL &&
745 (msgp = strstr(msgp, "] ")) != NULL) {
746 cp = msgp + 2;
747 }
748
749 /*
750 * Using console_printf instead of printf to avoid
751 * queueing messages to log_consq.
752 */
753 console_printf("%s", cp);
754 }
755 } while ((qlast = q) != qfirst);
756 }
757
758 /* ARGSUSED */
759 static int
log_cons_constructor(void * buf,void * cdrarg,int kmflags)760 log_cons_constructor(void *buf, void *cdrarg, int kmflags)
761 {
762 struct log *lp = buf;
763
764 lp->log_zoneid = GLOBAL_ZONEID;
765 lp->log_major = LOG_CONSMIN; /* Indicate which device type */
766 lp->log_data = NULL;
767 return (0);
768 }
769
770 /* ARGSUSED */
771 static void
log_cons_destructor(void * buf,void * cdrarg)772 log_cons_destructor(void *buf, void *cdrarg)
773 {
774 struct log *lp = buf;
775
776 ASSERT(lp->log_zoneid == GLOBAL_ZONEID);
777 ASSERT(lp->log_major == LOG_CONSMIN);
778 ASSERT(lp->log_data == NULL);
779 }
780